zoukankan      html  css  js  c++  java
  • 树状数组的几个模板

    一:单点修改区间求和,最裸的题

    题目链接:https://www.luogu.com.cn/problem/P3374

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn=500000+10;
    ll a[maxn],c[maxn];
    int n,m,i,j,q,x,y,k;
    
    void add(int i,int x){
    	while (i<=n){
    		c[i]+=x;i+=(i&-i);
    	}
    }
    
    ll sum(int i){
        ll res=0;
    	while (i>0){
    		res+=c[i];i-=(i&-i);
    	}
    	return res;
    }
    
    int main(){
    	std::ios::sync_with_stdio(false);
    	cin>>n>>m;
    	for (i=1;i<=n;i++){
    		cin>>a[i];add(i,a[i]);
    	}
    	for (i=1;i<=m;i++){
    		cin>>q;
    		if (q==1){
    			cin>>x>>k;add(x,k);
    		}
    		if (q==2){
    			cin>>x>>y;cout<<sum(y)-sum(x-1)<<endl;
    		}
    	}
    	return 0;
    }
    

    二:区间修改单点求和

    题目链接:https://www.luogu.com.cn/problem/P3368

    利用差分转化为第一种情况即可

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int maxn=500000+10;
    ll a[maxn],c[maxn];
    int n,m,i,j,k,q,x,y;
    
    void add(int i,int x){
    	while (i<=n){
    		c[i]+=x;i+=(i&-i);
    	}
    }
    
    ll sum(ll i){
    	ll res=0;
    	while (i>0){
    		res+=c[i];i-=(i&-i);
    	}
    	return res;
    }
    
    int main(){
    	std::ios::sync_with_stdio(false);
    	cin>>n>>m;
    	for (i=1;i<=n;i++){
    		cin>>a[i];
    		add(i,a[i]);add(i+1,-a[i]);
    	} 
    	for (i=1;i<=m;i++){
    		cin>>q;
    		if (q==1){
    			cin>>x>>y>>k;
    			add(x,k);add(y+1,-k);
    		}
    		if (q==2){
    			cin>>x;
    			cout<<sum(x)<<endl;
    		}
    	}
    	return 0;
    }
    

    三:求逆序对

    题目链接:https://vjudge.net/problem/POJ-2299

    倒序扫描数组a,核心代码只有 ans+=ask(a[i]-1); add(a[i],1)。有时数据大了要离散化

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    using namespace std;
    
    const int N=500010;
    int c[N],a[N],x[N];
    int n,i,j,k,m;
    
    int lowbit(int y) {return y&(-y);}
    void add(int x,int y) {while (x<=n){c[x]+=y; x+=lowbit(x);}}
    int ask(int x){
        int res=0;
    	while (x>0)	{res+=c[x]; x-=lowbit(x);}
    	return res;
    }
    
    int main(){
    	while (scanf("%d",&n)&&(n!=0)){
    	  for (i=1;i<=n;i++) {scanf("%d",&a[i]); x[i]=a[i]; c[i]=0;}
    	  sort(x+1,x+n+1); 
    	  for (i=1;i<=n;i++) a[i]=lower_bound(x+1,x+n+1,a[i])-x;
    	  ll ans=0;
    	  for (i=n;i>=1;i--){
    	  	ans+=ask(a[i]-1);
    	  	add(a[i],1);
    	  }
    	  printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    四:二维树状数组的单点修改,区间求和

    题目链接:https://vjudge.net/problem/POJ-1195

    模板题。但是有一个地方一开始写错了,就是询问区域和的式子,这个以后要注意

    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    const int N=1100;
    int c[N][N],s,I,x,y,a,l,b,r,t;
    
    int lowbit(int x){ return x&(-x);}
    void add(int u,int v,int d){
    	for (int i=u;i<=s;i+=lowbit(i))
    	  for (int j=v;j<=s;j+=lowbit(j)) c[i][j]+=d;
    }
    int ask(int u,int v){
    	int res=0;
    	for (int i=u;i>0;i-=lowbit(i))
    	  for (int j=v;j>0;j-=lowbit(j)) res+=c[i][j];
    	return res;
    }
    
    int main(){
    	scanf("%d",&I);
    	while (I!=3){
    	  if (I==0){scanf("%d",&s); memset(c,0,sizeof(c));}
    	  if (I==1){
    	  	scanf("%d%d%d",&x,&y,&a); x++;y++; 
    		add(x,y,a);
    	  }
    	  if (I==2){
    	  	scanf("%d%d%d%d",&l,&b,&r,&t); l++;b++;r++;t++;
    	  	printf("%d
    ",ask(r,t)-ask(r,b-1)-ask(l-1,t)+ask(l-1,b-1));
    	  }
    	  scanf("%d",&I);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    CodeForces 604D 【离散数学 置换群】
    CodeForces 604C 【思维水题】`
    CodeForces 602E【概率DP】【树状数组优化】
    CodeForces 602D 【单调队列】【简单数学】
    HDU 3535 【背包】
    CodeForces 593D【树链剖分】
    HYSBZ 1036 【树链剖分】
    POJ 2352 【树状数组】
    POJ 2182【树状数组】
    机器学习实战笔记-2-7分类机器学习形象化总结
  • 原文地址:https://www.cnblogs.com/edmunds/p/13620359.html
Copyright © 2011-2022 走看看