[学习笔记]树状数组

普通的树状数组想必大家应该很熟悉了.今天来简单地谈谈树状数组的区修区查.

一维树状数组

\(\varDelta_x\)表示区间\([x,n]\)的共同增量.
利用的差分的思想,对于区间\([l,r]\),每次修改\(\varDelta_l,\varDelta_{r+1}\)即可.
这就解决了区间加的问题.

考虑求和,\(a_x=a'_i+\sum_{i=1}^{x}\varDelta_i\)
\(\begin{split}s_x&=\sum_{i=1}^{x}a_i\\&=\sum_{i=1}^{x}a'_i+\sum_{i=1}^{x}(x-i+1)\varDelta_i\\&=\sum_{i=1}^{x}a'_i+\sum_{i=1}^{x}\varDelta_i\times(x+1)-\sum_{i=1}^{x}\varDelta_i\times{i}\end{split}\)
所以只需维护\(\varDelta_i,\varDelta_i\times{i}\)的前缀和即可.

struct BIT{
    int s[N];
    inline int lowbit(int x){
        return x&(-x);
    }
    lnline void add(int x,int k){
        if(!i) return;
        for(int i=x;i<=n;i+=lowbit(i))
            s[i]+=k;
    }
    lnline int ask(int x){
        int ret=0;
        for(int i=x;i;i-=lowbit(i))
            ret+=s[i];
        return ret;
    }
};
struct bit{
    BIT a,ai;int s[N];
    inline void init(){
        for(int i=1;i<=n;++i) s[i]=read();
        for(int i=1;i<=n;++i) s[i]+=s[i-1];
    }
    inline void add(int l,int r,int k){
        a.add(l,k);a.add(r+1,-k);
        ai.add(l,l*k);ai.add(r+1,-(r+1)*k);
    }
    inline void ask(int l,int r){
        return (s[r]+a.ask(r)*(r+1)-ai.ask(r))-(s[l-1]+a.ask(l-1)*l-ai.ask(l-1));
    }
}s;

二维树状数组

把刚刚的思想扩展到二维.
\(\varDelta_{x,y}\)表示区间\((x,y)-(n,n)\)的共同增量.
利用的差分的思想,对于区间\((x_l,y_l)-(x_r,y_r)\),每次修改\(\varDelta_{x_l,y_l},\varDelta_{x_r,y_l},\varDelta_{x_l,y_r},\varDelta_{x_r,y_r}\)即可.
考虑求和,\(a_{x,y}=a'_{x,y}+\sum_{i=1}^{x}\sum_{j=1}^{y}\varDelta_{i,j}\)
\(\begin{split}s_{x,y}&=\sum_{i=1}^{x}\sum_{j=1}^{y}a_{i,j}\\&=\sum_{i=1}^{x}\sum_{j=1}^{y}a'_{i,j}+\sum_{i=1}^{x}\sum_{j=1}^{y}(x-i+1)(y-j+1)\varDelta_{i,j}\\&=\sum_{i=1}^{x}\sum_{j=1}^{y}a'_{i,j}+\sum_{i=1}^{x}\sum_{j=1}^{y}(x+1)(y+1)\varDelta_{i,j}\\&\;\;\;-\sum_{i=1}^{x}\sum_{j=1}^{y}(x+1)\times{j}\times\varDelta_{i,j}-\sum_{i=1}^{x}\sum_{j=1}^{y}(y+1)\times{i}\times\varDelta_{i,j}\\&\;\;\;+\sum_{i=1}^{x}\sum_{j=1}^{y}i\times{j}\times\varDelta_{i,j}\end{split}\)
所以只需维护\(\varDelta_{i,j},\varDelta_{i,j}\times{j},\varDelta_{i,j}\times{i},\varDelta_{i,j}\times{i}\times{j}\)的前缀和即可.

struct BIT{
	int s[N][N];
	inline int lowbit(int x){
		return x&(-x);
	}
	inline void add(int x,int y,int k){
		for(int i=x;i<=n;i+=lowbit(i))
			for(int j=y;j<=n;j+=lowbit(j))
				s[i][j]+=k;
	}
	inline int ask(int x,int y){
		int ret=0;
		for(int i=x;i;i-=lowbit(i))
			for(int j=y;j;j-=lowbit(j))
				ret+=s[i][j];
		return ret;
	}
};
struct bit{
	BIT a,ai,aj,aij;int s[N][N];
	void init(){
		for(int i=1;i<=n;++i)
		    for(int j=1;j<=n;++j)
		        s[i][j]=read();
	    for(int i=1;i<=n;++i)
	        for(int j=1;j<=n;++j)
	            s[i][j]+=s[i][j-1];
	    for(int i=1;i<=n;++i)
	        for(int j=1;j<=n;++j)
	            s[i][j]+=s[i-1][j];
	}
	inline void Add(int x,int y,int k){
	    a.add(x,y,k);ai.add(x,y,-x*k);aj.add(x,y,-y*k);aij.add(x,y,x*y*k);
	}
	inline void add(int a,int b,int c,int d,int k){
	    Add(a,b,k);Add(c+1,b,-k);Add(a,d+1,-k);Add(c+1,d+1,k);
	}
	inline int Ask(int x,int y){
	    return s[x][y]+a.ask(x,y)*(x+1)*(y+1)+ai.ask(x,y)*(y+1)+aj.ask(x,y)*(x+1)+aij.ask(x,y);
	}
	inline int ask(int a,int b,int c,int d){
	    return Ask(c,d)-Ask(a-1,d)-Ask(c,b-1)+Ask(a-1,b-1);
	}
}s;

2017-04-09 00:07:20

原文地址:https://www.cnblogs.com/AireenYe/p/15605640.html