zoukankan      html  css  js  c++  java
  • 二叉索引树

    树状数组

    又名二叉索引树,是一种与线段树相似的数据结构
    他们能使对一个区间的数修改以及查询的速度提升许多

    树状数组模板1

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    int tree[2333333];
    int sum[233333];
    int a[2333333];
    int n,m;
    
    #define lowbit(x)  (x&(-x))
    
    inline void init()
    {
    	for(int x,i=1;i<=n;i++)
    	{
    		cin>>x;
    		sum[i]=sum[i-1]+x;
    		tree[i]=sum[i]-sum[i-lowbit(i)];
    	}
    }
    
    inline void add(int a,int val)
    {
    	while(a<=n)
    	{
    		tree[a]+=val;
    		a+=lowbit(a);
    	}
    }
    
    inline int query(int a)
    {
    	int res=0;
    	
    	while(a)
    	{
    		res+=tree[a];
    		a-=lowbit(a);
    	}
    	
    	return res;
    }
    
    int main()
    {
    	
    	
    	ios_base::sync_with_stdio(false);
    	cout.tie(NULL);
    	cin.tie(NULL);
    	
    	cin>>n>>m;
    	
    	init();
    	
    	for(int i=1;i<=m;i++)
    	{
    		int x,y,z;
    		
    		cin>>x>>y>>z;
    		
    		if(x == 1)
    		{
    			add(y,z);
    		}
    		else{
    			cout<<query(z)-query(y-1)<<'
    ';
    		}
    	}
    }
    

    中间有一个小小的卡常

    inline void init()
    {
    	for(int x,i=1;i<=n;i++)
    	{
    		cin>>x;
    		sum[i]=sum[i-1]+x;
    		tree[i]=sum[i]-sum[i-lowbit(i)];
    	}
    }
    

    该函数能将初始化树状数组的复杂度优化从O(nlogn)->O(n)



    树状数组模板2

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    int tree[2333333];
    int c[2333333];
    int n,m;
    
    inline int lowbit(int x) {return x&-x;}
    
    inline void add(int a,int val)
    {
    	while(a<=n)
    	{
    		tree[a]+=val;
    		a+=lowbit(a);
    	}
    }
    
    inline int query(int a)
    {
    	int res=0;
    	
    	while(a)
    	{
    		res+=tree[a];
    		a-=lowbit(a);
    	}
    	
    	return res;
    }
    
    int main()
    {
    	
    	ios_base::sync_with_stdio(false);
    	cout.tie(NULL);
    	cin.tie(NULL);
    	
    	cin>>n>>m;
    	
    	for(int i=1;i<=n;i++)
    	{
    		cin>>c[i];
    	}
    	
    	for(int i=1;i<=m;i++)
    	{
    		int l,x,y,z;
    		
    		cin>>l;
    		if(l == 1)
    		{
    			cin>>x>>y>>z;
    			add(x,z);
    			add(y+1,-z);
    		}
    		else
    		{
    			cin>>x;
    			int U=query(x)+c[x];
    			cout<<U<<'
    ';
    		}
    	}
    }
    
    • 对序列进行区间修改
    • 我们使用了另一个树状数组来辅助修改
    • 记录左右端点的修改
    • 当我们访问b的前缀和时
    • 就相当于访问之前操作对[1~x]的影响

    线段树模板1

    #include<iostream>
    #include<cstdio>
    
    using namespace std;
    
    const long long  maxn=1e5+5;
    
    long long  n,m;
    long long  sum[maxn];
    long long  tree[2][maxn];
    
    inline long long  lowbit(long long  x) {return x&-x;}
    
    inline void add(long long  k,long long  a,long long  val)
    {
    	
    	while(a<=n)
    	{
    		tree[k][a]+=val;
    		a+=lowbit(a);
    	}
    
    }
    
    inline long long  query(long long  k,long long  a)
    {
    	long long  res=0;
    	
    	while(a)
    	{
    		res+=tree[k][a];
    		a-=lowbit(a);
    	}
    	
    	return res;
    }
    
    
    
    int main()
    {
    	
    	
    	cin>>n>>m;
    	
    	long long  x;
    	
    	for(long long  i=1;i<=n;i++)
    	{
    		cin>>x;
    		sum[i]=sum[i-1]+x;
    	}	
    	
    	for(long long  i=1,x,y,z,g;i<=m;i++)
    	{
    		cin>>x>>y>>z;
    		if(x == 1)
    		{
    			cin>>g;
    			add(1,y,g);
    			add(1,z+1,-g);
    			add(0,y,y*g);
    			add(0,z+1,-(z+1)*g);
    		}
    		else{
    			cout<<(sum[z]+(z+1)*query(1,z)-query(0,z))-(sum[y-1]+y*query(1,y-1)-query(0,y-1))<<'
    ';
    		}
    	}
    }
    

    对单点查询=访问原值+b树状数组前缀和
    所以区间查询相当于对多个点进行单点查询
    那么a前缀和整体增加值为
    (sum_{i=1}^x{sum_{j=1}^i{b[j]}})
    (sum_{i=1}^x{sum_{j=1}^i{b[j]}} = sum_{i=1}^x{(x-i+1)*b[i]} = (x+1)sum_{i=1}^xb[i] - sum_{i=1}^x{i*b[i]})

    所以我们增加一个树状数组,维护 (i*b[i])的前缀和(sum_{i=1}^x{i*b[i]})

    另外我们维护原数组前缀和sum,对于每条 Q l r
    可得出
    访问原值前缀和与上述两个树状数组的值在套用上式与另一端点作差即可得出答案


    end

  • 相关阅读:
    MySQL+Navicat for MySQL安装
    intellij idea14 +svn配置
    java重载(实现同一方法名,不同参数)
    Java连接MySQL数据库及操作
    通过Chrome的inspect对手机webview进行调试
    使用fiddler对手机上的程序进行抓包
    开始一个Android的appium实例
    Android模拟器内安装应用
    Appium的inspector使用
    python webdriver启动IE浏览器
  • 原文地址:https://www.cnblogs.com/-Iris-/p/13278466.html
Copyright © 2011-2022 走看看