算法笔记--树状数组
区间和模板:
const int N=1e5+5; int c[N]; int n; int lowbit(int x) { return x&(-x); } int sum(int x) { int ret=0; while(x) { ret+=c[x]; x-=lowbit(x); } return ret; } void update(int x,int d) { while(x<=n) { c[x]+=d; x+=lowbit(x); } }
1.单点更新,区间求和
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e5+5; int c[N]; int n; int lowbit(int x) { return x&(-x); } int sum(int x) { int ret=0; while(x) { ret+=c[x]; x-=lowbit(x); } return ret; } void update(int x,int d) { while(x<=n) { c[x]+=d; x+=lowbit(x); } } int main() { ios::sync_with_stdio(false); cin.tie(0); int T,a,l,r; int cnt=0; string s; cin>>T; while(T--) { cin>>n; mem(c,0); for(int i=1;i<=n;i++)cin>>a,update(i,a); cout<<"Case "<<++cnt<<":"<<endl; while(cin>>s) { if(s=="End")break; if(s=="Query") { cin>>l>>r; cout<<sum(r)-sum(l-1)<<endl; } else if(s=="Add") { cin>>l>>r; update(l,r); } else if(s=="Sub") { cin>>l>>r; update(l,-r); } } } return 0; }
2.区间更新,单点求值
有点像差分标记
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e5+5; int c[N]; int n; int lowbit(int x) { return x&(-x); } int sum(int x) { int ret=0; while(x) { ret+=c[x]; x-=lowbit(x); } return ret; } void update(int x,int d) { while(x<=n) { c[x]+=d; x+=lowbit(x); } } int main() { ios::sync_with_stdio(false); cin.tie(0); int l,r; while(cin>>n) { mem(c,0); for(int i=1;i<=n;i++) { cin>>l>>r; update(l,1); update(r+1,-1); } for(int i=1;i<=n;i++) { cout<<sum(i); if(i!=n)cout<<' '; else cout<<endl; } } return 0; }
3.逆序数问题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e5+5; int c[N]; int n; int lowbit(int x) { return x&(-x); } int sum(int x) { int ret=0; while(x) { ret+=c[x]; x-=lowbit(x); } return ret; } void update(int x,int d) { while(x<=n) { c[x]+=d; x+=lowbit(x); } } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; while(cin>>n) { mem(c,0); int tot=0; for(int i=1;i<=n;i++) { cin>>t; update(t,1); tot+=i-sum(t);//sum(t)是小于等于t的个数 } cout<<tot<<endl; } return 0; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e5+5; int n; struct { int cnt; ll sum; }c[N]; int lowbit(int x) { return x&(-x); } ll _sum(int x) { ll ret=0; while(x) { ret+=c[x].sum; x-=lowbit(x); } return ret; } int cnt(int x) { int ret=0; while(x) { ret+=c[x].cnt; x-=lowbit(x); } return ret; } void update(int x,int d,int _d) { while(x<=n) { c[x].sum+=d; c[x].cnt+=_d; x+=lowbit(x); } } int main() { ios::sync_with_stdio(false); cin.tie(0); int t; while(cin>>n) { for(int i=1;i<=n;i++)c[i].sum=c[i].cnt=0; ll sum=0; for(int i=1;i<=n;i++) { cin>>t; update(t,t,1); sum+=((ll)t*(i-cnt(t))+_sum(n)-_sum(t)); } cout<<sum<<endl; } return 0; }
4.多维树状数组
二维:
树状数组+容斥
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e3+5; int n; bool vis[N][N]={false}; int c[N][N]; int lowbit(int x) { return x&(-x); } void update(int x,int y,int d) { for(int i=x;i<N;i+=lowbit(i)) { for(int j=y;j<N;j+=lowbit(j)) { c[i][j]+=d; } } } int sum(int x,int y) { int ret=0; for(int i=x;i>0;i-=lowbit(i)) { for(int j=y;j>0;j-=lowbit(j)) { ret+=c[i][j]; } } return ret; } int main() { ios::sync_with_stdio(false); cin.tie(0); int x,y,_x,_y; string s; while(cin>>n) { mem(c,0); mem(vis,false); for(int i=1;i<=n;i++) { cin>>s; if(s=="B") { cin>>x>>y; x++; y++; if(!vis[x][y])update(x,y,1),vis[x][y]=true; } else if(s=="D") { cin>>x>>y; x++; y++; if(vis[x][y])update(x,y,-1),vis[x][y]=false; } else if(s=="Q") { cin>>x>>_x>>y>>_y; x++,y++,_x++,_y++; if(x>_x)swap(x,_x); if(y>_y)swap(y,_y); cout<<sum(_x,_y)+sum(x-1,y-1)-sum(x-1,_y)-sum(_x,y-1)<<endl; } } } return 0; }
三维:
区间更新,单点求值
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=105; int a[N][N][N]; int n; int lowbit(int x) { return x&(-x); } void update(int x,int y,int z) { for(int i=x;i<=n;i+=lowbit(i)) { for(int j=y;j<=n;j+=lowbit(j)) { for(int k=z;k<=n;k+=lowbit(k)) { a[i][j][k]++; } } } } ll sum(int x,int y,int z) { ll res=0; for(int i=x;i>0;i-=lowbit(i)) { for(int j=y;j>0;j-=lowbit(j)) { for(int k=z;k>0;k-=lowbit(k)) { res+=a[i][j][k]; } } } return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); int x,y,z,_x,_y,_z; int t,m; while(cin>>n>>m) { mem(a,0); while(m--) { cin>>t; if(t) { cin>>x>>y>>z>>_x>>_y>>_z; update(x,y,z); update(_x+1,y,z); update(x,_y+1,z); update(x,y,_z+1); update(x,_y+1,_z+1); update(_x+1,y,_z+1); update(_x+1,_y+1,z); update(_x+1,_y+1,_z+1); } else { cin>>x>>y>>z; cout<<sum(x,y,z)%2<<endl; } } } return 0; }
5.离散化树状数组
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=5e5+10; struct node { int v; int id; bool operator < (const node t) const { return v<t.v; } }a[N]; int mp[N]; int c[N]; int n; int lowbit(int x) { return x&(-x); } void update(int x,int d) { while(x<=n)c[x]+=d,x+=lowbit(x); } int sum(int x) { int res=0; while(x)res+=c[x],x-=lowbit(x); return res; } int main() { ios::sync_with_stdio(false); cin.tie(0); while(cin>>n&&n) { mem(c,0); for(int i=1;i<=n;i++) { cin>>a[i].v; a[i].id=i; } sort(a+1,a+n+1); for(int i=1;i<=n;i++)mp[a[i].id]=i; ll ans=0; for(int i=1;i<=n;i++) { update(mp[i],1); ans+=i-sum(mp[i]); } cout<<ans<<endl; } return 0; }
6.区间更新,区间查询
不错的博客:https://www.cnblogs.com/lcf-2000/p/5866170.html
模板:
const int N=1e6+5; ll c1[N],c2[N]; int n; void add(int x,int y) { for(int i=x;i<=n;i+=i&(-i))c1[i]+=y,c2[i]+=(ll)x*y; } ll sum(int x) { ll ans=0; for(int i=x;i>0;i-=i&(-i))ans+=c1[i]*(x+1)-c2[i]; return ans; }
http://codevs.cn/problem/1082/
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) const int N=1e6+5; ll c1[N],c2[N]; int n; void add(int x,int y) { for(int i=x;i<=n;i+=i&(-i))c1[i]+=y,c2[i]+=(ll)x*y; } ll sum(int x) { ll ans=0; for(int i=x;i>0;i-=i&(-i))ans+=c1[i]*(x+1)-c2[i]; return ans; } int main() { ios::sync_with_stdio(false); cin.tie(0); int t,q,a,b,x; cin>>n; for(int i=1;i<=n;i++) { cin>>t; add(i,t); add(i+1,-t); } cin>>q; while(q--) { cin>>t; if(t==1) { cin>>a>>b>>x; add(a,x); add(b+1,-x); } else if(t==2) { cin>>a>>b; cout<<sum(b)-sum(a-1)<<endl; } } //for(int i=1;i<=n;i++)cout<<c1[i]<<' '<<c2[i]<<endl; return 0; }
参考博客:http://blog.csdn.net/yexiaohhjk/article/details/51077545