1 条题解

  • 0
    @ 2025-8-24 21:57:01

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar PurpleWonder
    **

    搬运于2025-08-24 21:57:01,当前版本为作者最后更新于2018-08-30 14:37:31,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    通过平衡树来维护区间操作的一道比较像模板的题目。

    看见楼上的几位大佬用的都是splay,补一发fhq_treap的题解好了。

    #include<cstdio>
    #include<iostream>
    #define ls(x) t[x].ch[0]
    #define rs(x) t[x].ch[1]
    using namespace std;
    
    struct node{
        int size,key,val,cx,add,tur,ch[2],maxn;
    }t[100010];
    //size:子树大小 key:随机生成的key值 val:当前位置的值 cx:在数组中的位置(好像后面没用到?) add:加法的延迟标记 tur:旋转的延迟标记 ch:左右儿子(用ls(x)与rs(x)表示) maxn:区间的最大值 
    int n,m,gs,rt;
    int seed=623; 
    int com,l,r,zhi;
    
    inline int rand(){
        return seed=(int)((seed*1000000007ll)%0x7fffffff);
    }
    //从下向上推时,需要同时更新两个值:最大值与子树大小 
    inline void push_up(int x){
        t[x].size=t[ls(x)].size+t[rs(x)].size+1;
        t[x].maxn=t[x].val;
        //防止在最大值为负值时访问到空节点(空节点处最大值为0) 
        if(ls(x))t[x].maxn=max(t[x].maxn,t[ls(x)].maxn);
        if(rs(x))t[x].maxn=max(t[x].maxn,t[rs(x)].maxn);
    }
    //向下推同样需要维护两个值:加的lazy标记与旋转的lazy标记 
    inline void push_down(int x){
        if(t[x].tur){
            if(ls(x))t[ls(x)].tur^=1;
            if(rs(x))t[rs(x)].tur^=1;
            ls(x)^=rs(x)^=ls(x)^=rs(x);
            t[x].tur=0;
        }
        if(t[x].add){
            if(ls(x)){//防止给0节点加上奇奇怪怪的值 
                t[ls(x)].add+=t[x].add;
                t[ls(x)].val+=t[x].add;
                t[ls(x)].maxn+=t[x].add;
            }
            if(rs(x)){
                t[rs(x)].add+=t[x].add;
                t[rs(x)].val+=t[x].add;
                t[rs(x)].maxn+=t[x].add;
            }
            t[x].add=0;
            update(x);
        }
    }
    //正常的分离/合并 
    int merge(int x,int y){
        int now;
        push_down(x);push_down(y);
        if(!x || !y)return x|y;
        if(t[x].key<t[y].key){
            now=x,rs(x)=merge(t[x].ch[1],y);
        }
        else now=y,ls(y)=merge(x,t[y].ch[0]);
        push_up(now);
        return now;
    }
    
    void split(int root,int bz,int &x,int &y){
        if(!root){x=y=0;return;}
        push_down(root);
        if(t[ls(root)].size>=bz)y=root,split(ls(root),bz,x,ls(y));
        else x=root,split(rs(root),bz-t[ls(root)].size-1,rs(x),y);
        push_up(root);
    }
    
    inline void insert(int x){
        t[++gs].key=rand();
        t[gs].val=x;
        t[gs].cx=gs;
        t[gs].maxn=x;
        t[gs].size=1;
        rt=merge(rt,gs);
    }
    //对l-r这段区间进行操作时,只需要先把l-r这段区间单独分离出来,再在分出来的区间的根节点上加lazy标记即可 
    inline void update1(int l,int r,int zhi){
        int x,y,z;
        split(rt,l-1,x,y);
        split(y,r-l+1,y,z);
        t[y].maxn+=zhi;
        t[y].add+=zhi;
        t[y].val+=zhi;
        rt=merge(merge(x,y),z);
    }
    
    inline void update2(int l,int r){
        int x,y,z;
        split(rt,l-1,x,y);
        split(y,r-l+1,y,z);
        t[y].tur^=1;
        rt=merge(merge(x,y),z);
    }
    
    inline void query(int l,int r){
        int x,y,z;
        split(rt,l-1,x,y);
        split(y,r-l+1,y,z);
        printf("%d\n",t[y].maxn);
        rt=merge(merge(x,y),z);
    }
    
    int main(){
        scanf("%d %d",&n,&m); 
        for(int i=1;i<=n;i++){
            insert(0);
        }
        while(m--){
            scanf("%d",&com);
            if(com==1){scanf("%d %d %d",&l,&r,&zhi),update1(l,r,zhi);}
            else if(com==2){scanf("%d %d",&l,&r),update2(l,r);}
            else if(com==3){scanf("%d %d",&l,&r),query(l,r);}
        }
        return 0;
    }
    
    • 1

    信息

    ID
    3102
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者