luogu3374/3368 树状数组

2021-07-15 22:06

阅读:577

标签:单点   printf   std   表示   技术分享   clu   define   gif   long   

现在才学树状数组...太惭愧了...而且并没有弄懂原理

设lowbit(x)表示的是把x的二进制只留下最低一位的1,然后lowbit(x)=x&(-x) (我也不知道为什么)

设c[x]表示从i往前一共lowbit(x)个数的和,那么x-lowbit(x)就是c[x]表示的范围的前一个数。

然后可以得到c[x]=c[x-lowbit(x)+lowbit(x)>>1]+c[x-lowbit(x)+lowbit(x)>>1+lowbit(x)>>2]+c[x-lowbit(x)+lowbit(x)>>1+lowbit(x)>>2+lowbit(x)>>3]....+c[x-1]+a[x]。

也就是说,如果将这个关系做成一个树,x的父亲就是x+lowbit(x)(观察一下上面的式子,很容易发现每一项都满足)

要询问1到x的和的话,只要一直加c[x],然后让x-=lowbit(x)直到x=0就好了

然后要修改一个点x的话,就一直往上修改它的父亲直到x>n就可以了。

也就是说,最基本的树状数组支持的是单点修改和前缀和查询,然后前缀和可以很容易地做成区间和(端点减一减)。

技术分享图片技术分享图片
 1 #include 2 #include 3 #include
 4 #define lowbit(x) ((x)&(-(x)))
 5 #define LL long long int
 6 const int maxn=500050;
 7 
 8 inline int rd(){
 9     int x=0;char c=getchar();int neg=1;
10     while(c‘0||c>9){if(c==-) neg=-1;c=getchar();}
11     while(c>=0&&c‘9) x=x*10+c-0,c=getchar();
12     return x*neg;
13 }
14 
15 int N,M;
16 LL c[maxn];
17 
18 inline void add(int x,int y){
19     while(x&&xlowbit(x);
20 }
21 inline LL query(int x){
22     LL re=0;while(x) re+=c[x],x-=lowbit(x);return re;
23 }
24 
25 int main(){
26     int i,j,k;
27     N=rd(),M=rd();
28     for(i=1;i) add(i,rd());
29     for(i=1;i){
30         int a=rd(),b=rd(),c=rd();
31         if(a==1) add(b,c);
32         else printf("%lld\n",query(c)-query(b-1));
33     }
34 }
View Code

 

也可以支持区间修改和单点查询,只要做一个差分,区间修改就变成了两个端点的修改,单点查询就变成了前缀和查询。

技术分享图片技术分享图片
 1 #include 2 #include 3 #include
 4 #define lowbit(x) ((x)&(-(x)))
 5 #define LL long long int
 6 const int maxn=500050;
 7 
 8 inline int rd(){
 9     int x=0;char c=getchar();int neg=1;
10     while(c‘0||c>9){if(c==-) neg=-1;c=getchar();}
11     while(c>=0&&c‘9) x=x*10+c-0,c=getchar();
12     return x*neg;
13 }
14 
15 int N,M;
16 LL c[maxn];
17 
18 inline void add(int x,int y){
19     while(x&&xlowbit(x);
20 }
21 inline LL query(int x){
22     LL re=0;while(x) re+=c[x],x-=lowbit(x);return re;
23 }
24 
25 int main(){
26     int i,j,k;
27     N=rd(),M=rd();
28     for(i=1,j=0;i){
29         k=rd();add(i,k-j);j=k;
30     };
31     for(i=1;i){
32         int a=rd(),b=rd();
33         if(a==1){
34             int c=rd(),d=rd();
35             add(b,d);add(c+1,-d);
36         }
37         else printf("%lld\n",query(b));
38     }
39 }
View Code

 

然后貌似区间修改和区间查询也是可以的,需要推一波式子

然后我选择线段树......

 

高级用法以后慢慢填

luogu3374/3368 树状数组

标签:单点   printf   std   表示   技术分享   clu   define   gif   long   

原文地址:https://www.cnblogs.com/Ressed/p/9533461.html


评论


亲,登录后才可以留言!