卧槽
厉害了,我的树状数组
1、单点修改,单点查询
用差分数组维护
#include<cstdio> #include<iostream> using namespace std; #define int long long #define M 1000500 #define lowbit(x) (x&(-x)) int c[M],flag,n,m; inline void add(int pos,int x) { for(int i=pos;i<=n;i+=lowbit(i)) c[i]+=x; } inline int query(int x) { int ans=0; for(int i=x;i;i-=lowbit(i)) ans+=c[i]; return ans; } signed main() { ios::sync_with_stdio(false); cin>>n>>m; int now=0,last=0; for(int i=1;i<=n;i++) { cin>>now; add(i,now-last); last=now; } int x; for(int i=1;i<=m;i++) { cin>>flag; if(flag==1) { int x,k; cin>>x>>k; add(x,k); add(x+1,-k); } else { cin>>x; cout<<query(x)<<endl; } } return 0; }
2、单点修改,区间查询(最原始的,最本质的)
#include<cstdio> #include<iostream> using namespace std; #define N 1000050 #define int long long int a[N],c[N],j; int n,m; inline int lowbit(int x) { return x&(-x); } inline void add(int x,int y) { while(x<=n) { c[x]+=y; x+=lowbit(x); } } inline int sum(int x) { int ace=0; while(x>=1) { ace+=c[x]; x-=lowbit(x); } return ace; } signed main() { ios::sync_with_stdio(false); cin>>n>>m; int x,y; for(int i=1;i<=n;i++) { cin>>a[i]; add(i,a[i]); } for(int i=1;i<=m;i++) { cin>>j>>x>>y; if(j==1) add(x,y); else cout<<sum(y)-sum(x-1)<<endl; } return 0; }
3、区间修改,单点查询
差分应用
#include<cstdio> #include<iostream> using namespace std; #define int long long #define M 1000500 #define lowbit(x) (x&(-x)) int c[M],flag,n,m; inline void add(int pos,int x) { for(int i=pos;i<=n;i+=lowbit(i)) c[i]+=x; } inline int query(int x) { int ans=0; for(int i=x;i;i-=lowbit(i)) ans+=c[i]; return ans; } signed main() { ios::sync_with_stdio(false); cin>>n>>m; int now=0,last=0; for(int i=1;i<=n;i++) { cin>>now; add(i,now-last); last=now; } int x; for(int i=1;i<=m;i++) { cin>>flag; if(flag==1) { int x,y,k; cin>>x>>y>>k; add(x,k); add(y+1,-k); } else { cin>>x; cout<<query(x)<<endl; } } return 0; }
4、区间修改,区间查询(niubilitiful)
观察式子:
a[1]+a[2]+...+a[n]
= (c[1]) + (c[1]+c[2]) + ... + (c[1]+c[2]+...+c[n])
= n*c[1] + (n-1)*c[2] +... +c[n]
= n * (c[1]+c[2]+...+c[n]) - (0*c[1]+1*c[2]+...+(n-1)*c[n]) (式子①)
那么我们就维护一个数组c2[n],其中c2[i] = (i-1)*c[i]
每当修改c的时候,就同步修改一下c2,这样复杂度就不会改变
那么
式子①
$=n*sum{(c,n)} - sum{(c2,n)}$
于是我们做到了在O(logN)的时间内完成一次区间和查询
#include<cstdio> #include<iostream> using namespace std; #define int long long #define M 1000500 #define lowbit(x) (x&(-x)) int c[M],flag,n,m; int s[M]; inline void add(int pos,int x) { for(int i=pos;i<=n;i+=lowbit(i)) { c[i]+=x; s[i]+=(pos-1)*x; } } inline int queryc(int x) { int ans=0; for(int i=x;i;i-=lowbit(i)) ans+=c[i]; return ans; } inline int querys(int x) { int ans=0; for(int i=x;i;i-=lowbit(i)) ans+=s[i]; return ans; } signed main() { ios::sync_with_stdio(false); cin>>n>>m; int now=0,last=0; for(int i=1;i<=n;i++) { cin>>now; add(i,now-last); last=now; } for(int i=1;i<=m;i++) { cin>>flag; if(flag==1) { int x,y,k; cin>>x>>y>>k; add(x,k); add(y+1,-k); } else { int x,y; cin>>x>>y; int tot1=y*queryc(y)-querys(y); int tot2=(x-1)*queryc(x-1)-querys(x-1); cout<<tot1-tot2<<endl; } } return 0; }
一件很好的事情就是树状数组的常数比其他NlogN的数据结构小得多,实际上它的计算次数比NlogN要小很多,再加上它代码短,是OI中的利器
厉害了~~~~~