树状数组(入门+一维+二维)
树状数组
int getsum(int x)
{
int ans=0;
for(int i=x;i>0;i-=lowbit(i))
ans+=C[i];
return ans;
}
void add(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
tree[i]+=y;
}
//可以发现 更新过程是查询过程的逆过程
//由叶子结点向上更新C[]数组
In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence
Ultra-QuickSort produces the output
Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence.InputThe input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 -- the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.OutputFor every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.Sample Input
5
9
1
0
5
4
3
1
2
3
0
Sample Output
6
0
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int maxn=1000010;
7 int t[maxn];
8 int lowbit(int x)
9 {
10 return x&(-x);
11 }
12 void update(int pos)
13 {
14 while(pos<maxn)
15 {
16 ++t[pos];
17 pos+=lowbit(pos);
18 }
19 }
20 long long query(int pos)
21 {
22 long long cnt=0;
23 while(pos>0)
24 {
25 cnt+=t[pos];
26 pos-=lowbit(pos);
27 }
28 return cnt;
29 }
30 int main()
31 {
32 int n;
33 while(~scanf("%d",&n))
34 {
35 if(n==0)
36 break;
37 memset(t,0,sizeof(t));
38 long long sum=0;
39 for(int i=0;i<n;i++)
40 {
41 int temp;
42 scanf("%d",&temp);
43 int count=query(temp+1);//temp+1防止出现0造成死循环
44 sum+=i-count;//count求出的是该数前面出现的比它小的数的个数,而本题让求逆序数,故用i-count
45 update(temp+1);
46 }
47 printf("%lld\n",sum);
48 }
49 return 0;
50 }
二维树状数组 单点更新 区间查询
设原始二维数组为:
A[][]={{a11,a12,a13,a14,a15,a16,a17,a18,a19},
{a21,a22,a23,a24,a25,a26,a27,a28,a29},
{a31,a32,a33,a34,a35,a36,a37,a38,a39},
{a41,a42,a43,a44,a45,a46,a47,a48,a49}};
记:
B[1]={a11,a11+a12,a13,a11+a12+a13+a14,a15,a15+a16,…} 这是第一行的一维树状数组
B[2]={a21,a21+a22,a23,a21+a22+a23+a24,a25,a25+a26,…} 这是第二行的一维树状数组
B[3]={a31,a31+a32,a33,a31+a32+a33+a34,a35,a35+a36,…} 这是第三行的一维树状数组
B[4]={a41,a41+a42,a43,a41+a42+a43+a44,a45,a45+a46,…} 这是第四行的一维树状数组
那么:
C[1][1]=a11,C[1][2]=a11+a12,C[1][3]=a13,C[1][4]=a11+a12+a13+a14,c[1][5]=a15,C[1][6]=a15+a16,… 这是A[][]第一行的一维树状数组
C[2][1]=a11+a21,C[2][2]=a11+a12+a21+a22,C[2][3]=a13+a23,C[2][4]=a11+a12+a13+a14+a21+a22+a23+a24,C[2][5]=a15+a25,C[2][6]=a15+a16+a25+a26,… 这是A[][]数组第一行与第二行相加后的树状数组
C[3][1]=a31,C[3][2]=a31+a32,C[3][3]=a33,C[3][4]=a31+a32+a33+a34,C[3][5]=a35,C[3][6]=a35+a36,…这是A[][]第三行的一维树状数组
C[4][1]=a11+a21+a31+a41,C[4][2]=a11+a12+a21+a22+a31+a32+a41+a42,C[4][3]=a13+a23+a33+a43,… 这是A[][]数组第一行+第二行+第三行+第四行后的树状数组
二维数组的规律就是,不管是横坐标还是纵坐标,将他们单独拿出来,他们都符合x += lowbit(x),属于它的父亲节点,即都符合那个经典的图。比如C[4][2]:
单独看横坐标(就是把纵坐标去掉,重复的只算一个):C[4] = C[2]+C[3]+a[4] (经典图得出)= a[1]+a[2]+a[3]+a[4] (从上面公式得出)
单独看纵坐标(就是把横坐标去掉,重复的只算一个):C[2] = C[1]+a[2] (经典图得出)= a[1]+a[2] (上面公式得出)
还不明白就多看几遍,体会一下,应该就懂了。
区间查询的话,调用一次query(x,y)显然是求(1,1) 到 (x,y)范围内矩形的和。观察下图,我们没办法一次查询出来给定区间的值,但是我们可以通过计算得出。
现在如果要查询蓝色范围内的和
调用A点是求紫色边框
调用B点是求绿色边框
调用C点是求黄色边框
调用D点是求红色边框
那么A-B-C+D即是答案。
接下来以hdu2642为模板题来写一下二维树状数组的单点更新,区间查询。
题意:一个星空,二维的。上面有1000*1000的格点,每个格点上有星星在闪烁。一开始时星星全部暗淡着,有M个操作:
B x y 点亮一盏星星
D x y 熄灭一盏星星
Q x1 x2 y1 y2 查询这个矩形里面亮着的星星的个数。
题解:这就是个二维树状数组单点更新、区间查询的模板题,直接写即可。不过有几个需要注意的地方。就像我在一维里说的,树状数组下标是从1开始维护的,所以我们要把数据偏移到下标从1开始,二维里也是一样。这里坐标可能为0,所以我们把每个坐标都++,然后就是点亮的星星不能重复点亮,暗淡的星星不能重复暗淡,设一个状态的数组即可。
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int maxn=1100;
7 int sz[maxn][maxn],status[maxn][maxn];
8 int lowbit(int x)
9 {
10 return x&(-x);
11 }
12 void update(int x,int y,int val)
13 {
14 for(int i=x;i<maxn;i+=lowbit(i))
15 {
16 for(int j=y;j<maxn;j+=lowbit(j))
17 {
18 sz[i][j]+=val;
19 }
20 }
21 }
22 int query(int x,int y)
23 {
24 int ans=0;
25 for(int i=x;i>0;i-=lowbit(i))
26 {
27 for(int j=y;j>0;j-=lowbit(j))
28 {
29 ans+=sz[i][j];
30 }
31 }
32 return ans;
33 }
34 int main()
35 {
36 int T;
37 cin>>T;
38 memset(sz,0,sizeof(sz));
39 memset(status,0,sizeof(status));
40 char ch;
41 int x1,x2,y1,y2;
42 while(T--)
43 {
44 getchar();
45 scanf("%c",&ch);
46 if(ch=='B')
47 {
48 scanf("%d%d",&x1,&y1);
49 x1++;
50 y1++;
51 if(status[x1][y1]==0)
52 {
53 update(x1,y1,1);
54 status[x1][y1]=1;
55 }
56 }
57 if(ch=='D')
58 {
59 scanf("%d%d",&x1,&y1);
60 x1++;
61 y1++;
62 if(status[x1][y1]>0)
63 {
64 update(x1,y1,-1);
65 status[x1][y1]=0;
66 }
67 }
68 if(ch=='Q')
69 {
70 scanf("%d%d%d%d",&x1,&x2,&y1,&y2);
71 x1++; y1++;
72 x2++; y2++;
73 if(x2<x1)
74 {
75 int t=x2;
76 x2=x1;
77 x1=t;
78 }
79 if(y2<y1)
80 {
81 int t=y2;
82 y2=y1;
83 y1=t;
84 }
85 printf("%d\n",query(x2,y2)-query(x2,y1-1)-query(x1-1,y2)+query(x1-1,y1-1));
86 }
87 }
88 }
参考博客:
http://www.cnblogs.com/hsd-/p/6139376.html
https://blog.csdn.net/WilliamSun0122/article/details/71642358