• [学习笔记]树状数组


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

    一维树状数组

    \(\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

  • 相关阅读:
    交叉熵的数学原理及应用——pytorch中的CrossEntropyLoss()函数
    pytorch中如何使用DataLoader对数据集进行批处理
    Pytorch中的自动求导函数backward()所需参数含义
    Pytorch中的torch.cat()函数
    Pytorch中的squeeze()和unsqueeze()函数
    UBUNTU18.04安装网易云音乐并直接图标启动
    UBUNTU18.4环境下使用更好用的搜索引擎(无奈,只能起这样的标题)
    Ubuntu 18.04换国内源 中科大源 阿里源 163源 清华源
    共享栈
    C++(十七) — 宏代码、内联函数
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15605640.html
Copyright © 2020-2023  润新知