zoukankan      html  css  js  c++  java
  • 树状数组

    对应线段树,补一下树状数组的笔记
    某乎上写的不错的树状数组

    1.树状数组原理

    树状数组.png
    蓝线为+ lowbit
    绿线为-lowbit

    树状数组最重要的原理

    树状数组本质上是前缀和(差分)之类的巴拉巴拉

    2.lowbit

    不理解,背过吧....

    int lowbit(int x){
    	return x&(-x);
    }
    

    3.修改点权(加减)

    没必要往下传值,类似于线段树,直接在父节点行修改

    void build(int x,int v){
    	for(int i = x; i<=n; i+= lowbit(i)){
    		tree[i]+=v;
    	}
    }
    

    4.区间求和

    前缀和的原理

    int query(int s,int e){
    	int ans1=0,ans2=0;
    	for(int i = s - 1; i > 0; i-=lowbit(i)) {
    		ans1+= tree[i];
    	}
    	for(int i = e; i > 0; i-=lowbit(i)) {
    		ans2+=tree[i];
    	}
    	return ans2-ans1;
    }
    

    树状数组 1模板

    //# 树状数组1 
    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N=5e5+10;
    int tree[N];
    int sum[N],a[N];
    int n,m; 
    int lowbit(int x){
    	return x&(-x);
    }
    int query(int s,int e){
    	int ans1=0,ans2=0;
    	for(int i = s - 1; i > 0; i-=lowbit(i)) {
    		ans1+= tree[i];
    	}
    	for(int i = e; i > 0; i-=lowbit(i)) {
    		ans2+=tree[i];
    	}
    	return ans2-ans1;
    }
    void build(int x,int v){
    	for(int i = x; i<=n; i+= lowbit(i)){
    		tree[i]+=v;
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    		add(i,a[i]);
    	}
    	for(int i= 1,tpy,x,w; i <=m;i++){
    		scanf("%d%d%d",&tpy,&x,&w);
    		if(tpy==1)
    			build(x,w);
    		else
    			printf("%d
    ",query(x,w));
    	}
    	return 0;
    }
    

    5.区间加

    差分的原理前缀和(貌似不怎么准确)
    给x的父亲加上,然后给y+1的父亲减去
    这样相当于进行了变区间加的操作一次给x后面的都加k,第二次给y+1后面的都减去k,把x多修改的区间都修回来

    ll add(ll x,ll v){
    	while(x <=n ){
    		tree[x]+=v;
    		x+=lowbit(x);
    	} 
    }
    
    scanf("%lld%lld%lld",&x,&y,&k);
    	add(x,k),add(y+1,-k);
    //x---y的区间都加+k
    

    数组数组2 模板

    #include<iostream>
    #include<cstdio>
    #define ll long long 
    using namespace std;
    const int N=5e5+10; 
    ll a[N],tree[N];
    int n,m;
    ll lowbit(ll x){
    	return x&(-x);
    }
    ll add(ll x,ll v){
    	while(x <=n ){
    		tree[x]+=v;
    		x+=lowbit(x);
    	} 
    }
    ll quert(ll x){
    	ll ans=0;
    	while(x>=1){
    		ans+=tree[x];
    		x-=lowbit(x); 
    	}
    	return ans;
    }
    int main(){
    	scanf("%lld%lld",&n,&m);
    	for(int i = 1; i <=n ; i++) {
    		scanf("%d",&a[i]);
    		add(i,a[i]-a[i-1]); 
    	} 
    	int tpy;
    	ll x,y,k;
    	for(int i = 1;i <= m ;i++){
    		cin>>tpy;
    		if(tpy==1){
    			scanf("%lld%lld%lld",&x,&y,&k);
    			add(x,k),add(y+1,-k);
    		}
    		if(tpy==2){
    			scanf("%lld",&x);
    			printf("%lld
    ",quert(x));
    		}
    	}
    	return 0;
    }
    	
    
  • 相关阅读:
    使用C++11实现线程池的两种方法
    二分查找算法的几种实现
    UNP多线程编程技巧简单总结
    使用带外数据设置 C/S 心跳机制
    无法修正错误,因为您要求某些软件包保持现状
    2012.12-操作系统-吕晓鑫-计算机操作系统综述
    2013.03-多核操作系统-梁荣晓-多核操作系统发展综述
    2011.09-多核操作系统-李彦冬-多核操作系统发展综述
    Simultaneous Multithreading: Maximizing On-Chip Parallelism(精读)
    Simultaneous Multithreading: Maximizing On-Chip Parallelism(泛读)
  • 原文地址:https://www.cnblogs.com/-wzd233/p/13911778.html
Copyright © 2011-2022 走看看