树状数组
单点修改,区间查询
#include<bits/stdc++.h> using namespace std; #define int long long #define lowbit(x) (x&(-x)) const int N=5e5+10; int a[N],s[N]; int n,m; void add(int x,int k){ for(int i=x;i<=n;i+=lowbit(i)){ s[i]+=k; } } int searchs(int l,int r){ int ans=0; for(int i=r;i;i-=lowbit(i)){ ans+=s[i]; } for(int i=l-1;i;i-=lowbit(i)){ ans-=s[i]; } return ans; } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; add(i,a[i]); } while(m--){ int op; cin>>op; if(op==1){ int x,k; cin>>x>>k; add(x,k); } else{ int l,r; cin>>l>>r; cout<<searchs(l,r)<<endl; } } }
区间修改,单点查询
存储差分数组,在区间+k就是把l位置+k,r+1位置-k,然后单点查询就是查询1到x的和
#include<bits/stdc++.h> using namespace std; #define int long long #define lowbit(x) (x&(-x)) const int N=5e5+10; int a[N],s[N]; int n,m; void add(int x,int k){ for(int i=x;i<=n;i+=lowbit(i)){ s[i]+=k; } } int searchs(int l,int r){ int ans=0; for(int i=r;i;i-=lowbit(i)){ ans+=s[i]; } for(int i=l-1;i;i-=lowbit(i)){ ans-=s[i]; } return ans; } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; add(i,a[i]-a[i-1]); } while(m--){ int op; cin>>op; if(op==1){ int x,y,k; cin>>x>>y>>k; add(x,k); add(y+1,-k); } else{ int x; cin>>x; cout<<searchs(1,x)<<endl; } } }
逆序对个数
数可能会很大,把他离散化,保留原有顺序,从左往右遍历,这样统计的是左边出现的比他大的数(即逆序对)
#include<bits/stdc++.h> using namespace std; #define int long long #define lowbit(x) (x&(-x)) const int N=5e5+10; int r[N],tr[N]; int n,m,ans; struct T{ int v,id; }a[N]; bool cmp(T a1,T a2){ if(a1.v==a2.v)return a1.id<a2.id; return a1.v<a2.v; } void add(int x,int k){ for(int i=x;i<=n;i+=lowbit(i)){ tr[i]+=k; } } int searchs(int l,int r){ int ans=0; for(int i=r;i;i-=lowbit(i)){ ans+=tr[i]; } for(int i=l-1;i;i-=lowbit(i)){ ans-=tr[i]; } return ans; } signed main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>a[i].v; a[i].id=i; } sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ r[a[i].id]=i; } for(int i=1;i<=n;i++){ int y=r[i]; ans+=searchs(1,n)-searchs(1,y); add(y,1); } cout<<ans<<endl; }
练习
楼兰图腾
#include<bits/stdc++.h> using namespace std; #define int long long #define lowbit(x) (x&(-x)) const int N=5e5+10; int a[N],s[N]; int llow[N],lgre[N]; int rlow[N],rgre[N]; int n,m; void add(int x,int k){ for(int i=x;i<=n;i+=lowbit(i)){ s[i]+=k; } } int searchs(int l,int r){ int ans=0; for(int i=r;i;i-=lowbit(i)){ ans+=s[i]; } for(int i=l-1;i;i-=lowbit(i)){ ans-=s[i]; } return ans; } signed main(){ cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; //从小打到遍历,统计的是每个数左边比它小的个数,和比他大的个数 for(int i=1;i<=n;i++){ int y=a[i]; llow[i]=searchs(1,y-1); lgre[i]=searchs(1,n)-searchs(1,y); add(y,1); } memset(s,0,sizeof(s)); //从右往左遍历,统计的是这个数右边比他大的和比他小的个数 int ans1=0,ans2=0; for(int i=n;i>=1;i--){ int y=a[i]; ans2+=llow[i]*searchs(1,y-1); ans1+=lgre[i]*(searchs(1,n)-searchs(1,y)); add(y,1); } cout<<ans1<<' '<<ans2<<endl; }
区间修改,区间查询
对于区间修改我们照样用差分存储改为单点修改,区间查询的话我们公式推导后可以发现需要另一个树状数组来存储i*d的差分来求前缀和
#include<bits/stdc++.h> using namespace std; #define int long long #define lowbit(x) (x&(-x)) const int N=5e5+10; int a[N],tr[N],tr2[N]; int n,m; void add(int tr[],int x,int k){ for(int i=x;i<=n;i+=lowbit(i)){ tr[i]+=k; } } int searchs(int tr[],int l,int r){ int ans=0; for(int i=r;i;i-=lowbit(i)){ ans+=tr[i]; } for(int i=l-1;i;i-=lowbit(i)){ ans-=tr[i]; } return ans; } int sum(int x){ return searchs(tr,1,x)*(x+1)-searchs(tr2,1,x); } signed main(){ cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; int d=a[i]-a[i-1]; add(tr,i,d); add(tr2,i,d*i); } while(m--){ char op; cin>>op; if(op=='Q'){ int l,r; cin>>l>>r; cout<<sum(r)-sum(l-1)<<endl; } else{ int l,r,d; cin>>l>>r>>d; add(tr,l,d);add(tr,r+1,-d); add(tr2,l,l*d);add(tr2,r+1,(r+1)*(-d)); } } }
谜一样的牛
#include<bits/stdc++.h> using namespace std; #define int long long #define lowbit(x) (x&(-x)) const int N=5e5+10; int a[N],tr[N]; int n,m,ans[N]; void add(int x,int k){ for(int i=x;i<=n;i+=lowbit(i)){ tr[i]+=k; } } int searchs(int l,int r){ int ans=0; for(int i=r;i;i-=lowbit(i)){ ans+=tr[i]; } for(int i=l-1;i;i-=lowbit(i)){ ans-=tr[i]; } return ans; } signed main(){ cin>>n; for(int i=2;i<=n;i++)cin>>a[i]; for(int i=1;i<=n;i++)add(i,1); for(int i=n;i>=1;i--){ int l=1,r=n; while(l<r){ int mid=l+r>>1; if(searchs(1,mid)>=a[i]+1){ r=mid; } else l=mid+1; } ans[i]=l; add(l,-1); } for(int i=1;i<=n;i++)cout<<ans[i]<<endl; }

浙公网安备 33010602011771号