线段树(四)——杨子曰算法

线段树(四)——杨子曰算法

传送门:线段树(三)


欧,现在是线段树模板题的最后一个大BOSS了,也就是更新的是区间,询问的也是区间,看上去很恶心,现在解决它!(我们把add(lazy)和sum记在一个struct,看得清晰)


首先,他询问的是区间和,So,最开始肯定要build,不多说:

void build(int l,int r,int nod){
    tree[nod].add = 0;
    if (l==r){
        tree[nod].sum=a[l];
        return;
    }
    int mid=(l+r)/2;
    build(l,mid,nod*2);
    build(mid+1,r,nod*2+1);
    tree[nod].sum=tree[nod*2].sum+tree[nod*2+1].sum;
}

再看update,这肯定得用lazy优化,就是区间吻合就完事,但更新sum的时候一定要注意区间吻合时,这个区间里的每一个元素可都得加上v,So,tree[nod].sum+=(r-l+1)*v
来看update:

void update(int l,int r,int ll,int rr,int v,int nod){
    if (l==ll &&r==rr){
        tree[nod].sum+=(r-l+1)*v;
        tree[nod].add+=v;
        return;
    }
    pushdown(nod, l, r);
    int mid=(l+r)/2;
    if (rr<=mid) update(l,mid,ll,rr,v,nod*2);
    else if (ll>=mid+1) update(mid+1,r,ll,rr,v,nod*2+1); 
    else {
        update(l,mid,ll,mid,v,nod*2);
        update(mid+1,r,mid+1,rr,v,nod*2+1);
    }
    pushup(nod);
}

这里有一个小问题pushdown怎么写,机智的大佬一定会写了,但我还要说一下,这个add是指对这个区间中的每个数都要加上它,那在计算左右儿子的sum的时候,要乘上儿子区间的对应元素个数(这也就是为什么pushdown要传l和r)

void pushdown(int nod, int l, int r) {
    int mid = (l+r)/2;
    tree[nod*2].sum+=(mid-l+1)*tree[nod].add;
    tree[nod*2+1].sum+=(r-mid)*tree[nod].add;
    tree[nod*2].add+=tree[nod].add;
    tree[nod*2+1].add+=tree[nod].add;
    tree[nod].add=0;
}

还有一个小问题,pushup怎么写?sum一定要pushup上去,那add呢?Of couse NOT!首先add本身记录的就是它儿子的变化量,再有,当你pushup的时候,你的add可是0诶,那你pushup什么鬼呢?

void pushup(int nod) {
    tree[nod].sum = tree[nod*2].sum + tree[nod*2+1].sum;
}

这样弄完了以后solve就简单了,更原来完全一样:

int solve(int l,int r,int ll,int rr,int nod){
    if (l==ll &&r==rr){
        return tree[nod].sum;
    }
    pushdown(nod, l, r);
    int mid=(l+r)/2;
    if (rr<=mid) return solve(l,mid,ll,rr,nod*2);
    else if(ll>=mid+1) return solve(mid+1,r,ll,rr,nod*2+1);
    else return solve(l,mid,ll,mid,nod*2)+solve(mid+1,r,mid+1,rr,nod*2+1);
}

OK!完事


啰嗦一下:
如果到目前为止,你对线段树一点问题都没有的话,Congratulations!——你终于略懂了线段树的皮毛,当然线段树的用处肯定不只是求求min,求求max,求求sum,之前也曰了线段树可以解决所有区间问题,对应的,线段树里记录的区间信息是不一样的

看道题:
给一个长度为n(n<=200000)的序列,再给出m个操作,对于每个操作,先给出一个k,如果k=1,则输入x,y,输出区间[x,y]中能被7整除的数的个数,如果k=2,则输入x,y,z,把区间[x,y]的每个元素加上z

好吧,最近写线段树写烦了,我也不知道什么时候再出线段树(五),等那时候再来给大家曰这道题吧!
OK,88

未经作者允许,严禁转载:

猜你喜欢

转载自blog.csdn.net/HenryYang2018/article/details/80014786