标签:turn 元素 生成树 数字 时间复杂度 c++ art 位置 现在
输入一个长度为n的数组,有以下两种操作:
1.输入一个数m,输出数组中下标1~m的前缀和
2.对指定下标的数值进行修改
我们有两种思路,一种是for循环累加,另一种是利用前缀和数组。两种算法多 次操作时间复杂度在O(n^2),我们不妨来用树状数组进行操作。
定义:是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和(维护前缀和),但是每次只能修改一个元素的值。(逻辑结构上是一棵树,但实际上只是个数组。)
其实还可以发现:层数k的值 = 数组C下标的二进制末尾0的个数= 数组C下标的二进制最后一个1的位置
了解了以上这些,我们就来看看关于值的修改和求取前缀和。下面先放两张图。
可以看到,我们以前所学的操作是对整个数值进行操作,所以时间复杂度高达O(n^2),而现在是求取部分和,时间复杂度就降低到O(nlogn)
int lowbit(int x) {
return x&(-x); //二进制补码与运算,一假即假
}
这是生成树状数组的函数(也是改变数组中数值的函数)
int change(int k,int value)
{
while(k<=n)
{
c[k]+=value;
k+=lowbit(k);
}
}
这是区间查询的函数
int sum(int i)
{
int s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}
int qujiansum(int a,int b)
{
return sum(b)-sum(a-1);
}
在数值原有的基础上改变值(其实和change函数一样)
void add (int i, int val) { //用add (i)表示A[i] + val
while (i <= n) {
c[i] += val;
i += lowbit(i);
}
}
关于这个函数:
add(i, -A[i]); //将A[i]的值删除
add(i, val); //修改为val
A[i] = val; //修改A[i]的值为val
下面给一个完整的求取前缀和代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=9999999;
int n,start,end,value;
int c[MAXN];
int lowbit(int x){
return x&(-x);
}
int change(int k,int value)
{
while(k<=n)
{
c[k]+=value;
k+=lowbit(k);
}
}
int sum(int i)
{
int s=0;
while(i>0)
{
s+=c[i];
i-=lowbit(i);
}
return s;
}
int qujiansum(int a,int b)
{
return sum(b)-sum(a-1);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>value;
change(i,value);
}
int q;
cin>>q;
for(int i=1;i<=q;i++){
cin>>start>>end;
cout<<qujiansum(start,end); }
return 0;
}
逆序数的简介:对于n个不同的元素,先规定各元素之间有一个标准次序(例如n个 不同的自然数,可规定从小到大为标准次序),于是在这n个元素的任一排列中,当某两个元素的先后次序与标准次序不同时,就说有1个逆序。一个排列中所有逆序总数叫做这个排列的逆序数。
举个例子来尝试理解:
先用暴力来做一下:
int ans = 0;
for (int i = 1; i <= n; i ++) {
for (int j = i + 1; j <= n; j ++) {
if (A[i] < A[j]) { //后面有多少个数比它小
ans ++;
}
}
}
可以看到,用暴力来做的话时间复杂度为O((n^2)/2) ≈ O(n^2)
那我们不妨再用树状数组来尝试下:
for (int i = n; i >= 1; i --) { //最后一个数后面没有数
ans += sum(A[i]-1); //A[i]-1排除相等的数
add (A[i], 1);
}
时间复杂度大大减少,为O(n2logn) ≈ O(n*logn)
在很多的情况下,线段树都可以用树状数组实现.凡是能用树状数组的一定能用线段树.当题目不满足减法原则的时候,就只能用线段树,不能用树状数组.例如数列操作如果让我们求出一段数字中最大或者最小的数字,就不能用树状数组了.
感谢明老师的教学
标签:turn 元素 生成树 数字 时间复杂度 c++ art 位置 现在
原文地址:https://www.cnblogs.com/Sure05/p/12878213.html