建树

对于维护长度为 \(n\) 的序列,底层至少 \(n+2\) 个点。\(t_{N+i}\) 就代表下标 \(i\) 对应的叶子节点。底层的第一个节点的编号就是 \(N\),它是一个虚点。

计算一下可知 \(N\) 最多增加到 \(2n+2\),由于我们需要用到 \(t_{N+n+1}\)(为什么后面再说),所以大约开三倍空间即可。

for(N=1;N<n+2;N<<=1);
for(int i=1;i<=n;++i)
    t[N+i]=read(9);
for(int i=N-1;i;--i) // 注意从 N-1 开始更新,否则会越界
    t[i]=t[i<<1]+t[i<<1|1];

单点修改,区间查询

void change(int o,int k) {
    for(t[N+o]=k,o=N+o>>1;o;o>>=1)
        t[o]=t[o<<1]+t[o<<1|1];
}

建立两个哨兵节点 \(l,r\) 代表区间 \([L,R]\)\(L-1,R+1\) 两个点。两个哨兵同时上移,如果 \(l\) 是左儿子,就将它对应的右儿子加入贡献。\(r\) 同理。

由于 \([L,R]\) 可能取到 \([1,n]\),所以 \(t_N,t_{N+n+1}\) 这两个虚点是必要的。

int ask(int l,int r) {
    int ret=0;
    for(l=N+l-1,r=N+r+1;l^r^1;l>>=1,r>>=1) {
        if(~l&1) ret+=t[l^1];
        if(r&1) ret+=t[r^1];
    }
    return ret;
}

区间修改,区间查询

先放一张图吧:

懒标记

维护 \(t\) 数组为区间和,\(la\) 数组是可持久化懒标记。

统计 \(ls,rs\) 分别为 \(l,r\) 向上跳时经过的 区间内 的点的个数,\(\text{all}\) 维护 \(l,r\) 跳跃当前层的节点个数。 当 \(l,r\) 成为某点的左右儿子时,也要继续往上更新。

void modify(int l,int r,int k) {
    int ls=0,rs=0,all=1;
    for(l=N+l-1,r=N+r+1;l^r^1;l>>=1,r>>=1,all<<=1) {
        t[l]+=k*ls,t[r]+=k*rs; // 此时的 ls,rs 已经是 l,r 的儿子部分了
        if(~l&1) {
            la[l^1]+=k; t[l^1]+=k*all;
            ls+=all;
        }
        if(r&1) {
            la[r^1]+=k; t[r^1]+=k*all;
            rs+=all;
        }
    }
    for(;l;l>>=1,r>>=1) 
        t[l]+=k*ls,t[r]+=k*rs;
}

询问同理。对于不查询完整区间的,用懒标记贡献;反之直接加上 \(t\) 数组即可。

int ask(int l,int r) {
	int ls=0,rs=0,all=1,ret=0;
    for(l=N+l-1,r=N+r+1;l^r^1;l>>=1,r>>=1,all<<=1) {
    	ret+=la[l]*ls+la[r]*rs;
        if(~l&1) ret+=t[l^1],ls+=all;
        if(r&1) ret+=t[r^1],rs+=all;
    }
    for(;l;l>>=1,r>>=1) 
        ret+=la[l]*ls+la[r]*rs;
    return ret;
}

差分

看了半天没有懂,于是就 咕咕咕 了。

区间修改,单点查询

此时将原数组当作懒标记数组来使用即可。代码十分简单。需要注意的是修改时,在 \(l,r\) 成为某点的左右儿子后就不再修改了。画画图可以知道此时已经将所修改区间到根的路径都打上了懒标记。

void modify(int l,int r,int k) {
    for(l=N+l-1,r=N+r+1;l^r^1;l>>=1,r>>=1) {
        if(~l&1) t[l^1]+=k;
        if(r&1) t[r^1]+=k;
    }
}

查询时将叶子到根的路径上懒标记累加即可。

int ask(int x) {
    int ret=0;
    for(x=N+x;x;x>>=1) ret+=t[x];
    return ret;
}
posted on 2021-10-08 14:58  Oxide  阅读(66)  评论(0编辑  收藏  举报