树状数组笔记
lowbit:保留数在2进制下最后一个1,前面全变0
模板1:单点修改,区间查询
# include <bits/stdc++.h> using namespace std; typedef long long ll; int n[500009]; int t,k; int lowbit(int m) { return m&-m; } void cr(int i,int x) { while(i<=t) { n[i]+=x; i+=lowbit(i); } } int show(int i) { int ans=0; while(i!=0) { ans+=n[i]; i-=lowbit(i); } return ans; } int main() { cin>>t>>k; for(int i=1;i<=t;i++) { int a; cin>>a; cr(i,a); } while(k--) { int a,b,c;cin>>a>>b>>c; if(a==1) cr(b,c); else if(a==2) cout<<show(c)-show(b-1)<<endl; } return 0; }
例题:Problem - 1679C - Codeforces
#include<stdio.h> #include<math.h> #include<string.h> #include<ctype.h> #include<iostream> #include<algorithm> #include<queue> typedef long long ll; using namespace std; int col[200005],row[200009]; int dc[200009],dr[200009]; int n,q; int lowbit(int x){ return x&(-x); } int query(int x,int k[]){ int s=0; for(;x;x-=lowbit(x)) s+=k[x]; return s; } void modify(int x,int s,int k[]){ for(;x<=n;x+=lowbit(x)) k[x]+=s; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0),std::cout.tie(0); cin>>n>>q; for(int i=0;i<q;i++){ int t;cin>>t; if(t==1){ int x,y;cin>>x>>y; if(!dc[x]) modify(x,1,col); if(!dr[y]) modify(y,1,row); dc[x]++,dr[y]++; } else if(t==2){ int x,y;cin>>x>>y; dc[x]--,dr[y]--; if(!dc[x])modify(x,-1,col); if(!dr[y])modify(y,-1,row); } else{ int x1,x2,y1,y2;cin>>x1>>y1>>x2>>y2; if(x2-x1+1==query(x2,col)-query(x1-1,col)||y2-y1+1==query(y2,row)-query(y1-1,row)) cout<<"Yes\n"; else cout<<"No\n"; } } }
模板2:区间修改,单点查询
利用差分思想完成
# include <bits/stdc++.h> using namespace std; typedef long long ll; int n[1000009],a[1000009]; int t,k; int lowbit(int m) { return m&(-m); } void update(int i,int x) { while(i<=t) { n[i]+=x; i+=lowbit(i); } } int getsum(int i) { int ans=0; while(i>0) { ans+=n[i]; i-=lowbit(i); } return ans; } int main() { cin>>t>>k; for(int i=1;i<=t;i++) { cin>>a[i]; update(i,a[i]-a[i-1]);//数组存的是差分数组 } while(k--) { int ty;cin>>ty; if(ty==2){ int l;cin>>l;cout<<getsum(l)<<"\n";//单点查询某个点数值 } else{ int l,r,k; cin>>l>>r>>k; update(r+1,-k);//对差分前缀和操作 update(l,k);// } } return 0; }
模板3
区间修改区间查询
比模板2多了个数组
#include<stdio.h> #include<math.h> #include<string.h> #include<ctype.h> #include<iostream> #include<algorithm> #include<queue> using namespace std; typedef long long ll; ll c[1000009],a[1000009],c2[1000009]; ll t,k; ll lowbit(ll m) { return m&(-m); } void update(ll x,ll d) { for(ll i=x;i<=t;i+=lowbit(i)){ c[i]+=d;c2[i]+=x*d; } } ll getsum(ll x) { ll ans1=0; ll ans2=0; for(ll i=x;i;i-=lowbit(i)){ ans1+=(x+1)*c[i];ans2+=c2[i]; } return abs(ans1-ans2); } int main() { cin>>t>>k; for(ll i=1;i<=t;i++) { cin>>a[i]; update(i,a[i]-a[i-1]);//数组存的是差分数组 } while(k--) { ll ty;cin>>ty; if(ty==2){ ll l,r;cin>>l>>r;cout<<getsum(r)-getsum(l-1)<<"\n";//单点查询某个点数值 } else{ ll l,r,k; cin>>l>>r>>k; update(r+1,-k);//对差分前缀和操作 update(l,k);// } } return 0; }
模板:二维树状数组单点修改,区间查询
# include <bits/stdc++.h> using namespace std; typedef long long ll; ll tree[4100][4100]; ll n,m,k; ll lowbit(ll m){ return m&(-m); } void change(ll x,ll y,ll k){ for(ll i=x;i<=n;i+=lowbit(i)){ for(ll j=y;j<=m;j+=lowbit(j)) tree[i][j]+=k; } } ll qurey(ll x,ll y){ ll ans=0; for(ll i=x;i;i-=lowbit(i)){ for(ll j=y;j;j-=lowbit(j)) ans+=tree[i][j]; } return ans; } int main(){ scanf("%lld%lld",&n,&m);ll mod; while(scanf("%lld",&mod)!=EOF){ if(mod==1){ ll x,y,k;cin>>x>>y>>k; change(x,y,k); } else{ ll x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2; cout<<(qurey(x2,y2)+qurey(x1-1,y1-1)-qurey(x1-1,y2)-qurey(x2,y1-1))<<endl; } } return 0; }