• P2041 [NOI2005]维护数列(Splay树支持插入区间、删除区间、修改区间、翻转区间、区间求和、区间带修改最大子列和的代码模板)


    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+100;
    const int inf=1e9;
    int root,tot;
    int a[maxn];
    int pos[maxn];
    int rub[maxn];
    int top;
    int n,m;
    
    struct Splay_tree {
        int ch[2];//左右儿子
        int size;//子树大小
        int fa;//父亲
        int tag;//赋值标记
        int v;//权值
        int rev;//翻转标记
        int sum;//区间权值和
        int left;//左区间,指区间最大前缀和 
        int right;//右区间,指区间最大后缀和
        int middle;//中区间,指区间最大字段和
        void clear () {
            ch[0]=ch[1]=fa=rev=tag=0;
        } 
    }t[maxn];
    int rubish () {
        //垃圾回收
        if (top==0) return ++tot;
        int tt=rub[top--];
        return tt; 
    }
    void change_val (int id,int v) {
        //更新点值
        if (!id) return;
        t[id].tag=t[id].v=v;//打标记 
        t[id].sum=v*t[id].size;//更新区间权值和 
        t[id].left=t[id].right=max(t[id].sum,0);//左右区间更新 
        t[id].middle=max(t[id].sum,v);//最大字段和更新 
    }
    void change_rev (int id) {
        //更新翻转
        swap(t[id].ch[0],t[id].ch[1]);//交换左右儿子 
        swap(t[id].left,t[id].right);//交换左右区间 
        t[id].rev^=1; //打翻转标记 
    }
    void pushup (int id) {
        //信息更新 
        Splay_tree &x=t[t[id].ch[0]];
        Splay_tree &y=t[t[id].ch[1]];
        int v=t[id].v;
        Splay_tree &wjm=t[id];
        wjm.sum=x.sum+y.sum+v;
        wjm.size=x.size+y.size+1;
        wjm.middle=max(max(x.middle,y.middle),x.right+y.left+v);
        wjm.left=max(x.left,x.sum+y.left+v);
        wjm.right=max(y.right,y.sum+x.right+v);
    } 
    void pushdown (int id) {
        //标记下传
        if (t[id].tag!=inf) {
            change_val(t[id].ch[0],t[id].tag);
            change_val(t[id].ch[1],t[id].tag);
            t[id].tag=inf;
        } 
        if (t[id].rev) {
            change_rev(t[id].ch[0]);
            change_rev(t[id].ch[1]);
            t[id].rev=0;
        }
    }
    void rotate (int x) {
        int y=t[x].fa;
        int z=t[y].fa;
        int k=(t[y].ch[1]==x);
        t[z].ch[t[z].ch[1]==y]=x;
        t[x].fa=z;
        t[y].ch[k]=t[x].ch[k^1];
        t[t[x].ch[k^1]].fa=y;
        t[x].ch[k^1]=y;
        t[y].fa=x;
        pushup(y);
        pushup(x);
    }
    void splay (int x,int s) {
        while (t[x].fa!=s) {
            int y=t[x].fa;
            int z=t[y].fa;
            if (z!=s) 
                (t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);
            rotate(x);
        }
        if (s==0) root=x;
    }
    void newNode (int id,int x) {
        t[id].middle=t[id].sum=x;
        t[id].tag=inf;
        t[id].rev=0;
        t[id].left=t[id].right=max(x,0);
        t[id].size=1;
    }
    void build (int l,int r,int fa) {
        //建树
        int mid=(l+r)>>1;
        int id=pos[mid];
        int pre=pos[fa];
        if (l==r) newNode(id,a[l]);
        if (l<mid)
            build(l,mid-1,mid);
        if (r>mid)
            build(mid+1,r,mid);
        t[id].v=a[mid];
        t[id].fa=pre;
        t[id].tag=inf;
        pushup(id);
        t[pre].ch[mid>=fa]=id; 
    }
    int kth (int x) {
        int id=root;
        while (1) {
            pushdown(id);
            if (t[t[id].ch[0]].size>=x)
                id=t[id].ch[0];
            else if (t[t[id].ch[0]].size+1==x)
                return id;
            else
                x-=t[t[id].ch[0]].size+1,id=t[id].ch[1];
        }
    }
    void remove (int id) {
        //删除一个子树 
        if (t[id].ch[0]) remove(t[id].ch[0]);
        if (t[id].ch[1]) remove(t[id].ch[1]);
        rub[++top]=id;
        t[id].clear(); 
    }
    int split (int k,int len) {
        //到目标区间的位置
        int x=kth(k);
        int y=kth(k+len+1);
        splay(x,0);
        splay(y,x);
        return t[y].ch[0]; 
    }
    void query (int x,int len) {
        //查询区间权值和
        int id=split(x,len);//先找到该区间
        printf("%d
    ",t[id].sum);
    }
    void update (int x,int len,int v) {
        //更新区间的值
        int id=split(x,len);
        int y=t[id].fa;
        change_val(id,v);
        pushup(y);
        pushup(t[y].fa); 
    }
    void reverse (int x,int len) {
        //翻转区间
        int id=split(x,len);
        int y=t[id].fa;
        if (t[id].tag!=inf) return;
        change_rev(id);//翻转该区间
        pushup(y);
        pushup(t[y].fa); 
    }
    void del (int x,int len) {
        //删除区间
        int id=split(x,len);
        int y=t[id].fa;
        remove(id);
        t[y].ch[0]=0;
        pushup(y);
        pushup(t[y].fa); 
    }
    void ins (int k,int len) {
        //插入区间
        for (int i=1;i<=len;i++) scanf("%d",&a[i]);
        for (int i=1;i<=len;i++) pos[i]=rubish();
        build(1,len,0);//将输入的区间建一颗树
        int p=pos[(1+len)>>1];
        int x=kth(k+1);
        int y=kth(k+2);//找到插入的位置
        splay(x,0);
        splay(y,x);
        t[p].fa=y;
        t[y].ch[0]=p;
        pushup(y);
        pushup(x); 
    }
    int main () {
        scanf("%d%d",&n,&m);
        t[0].middle=a[1]=a[n+2]=-inf;
        for (int i=1;i<=n;i++) scanf("%d",&a[i+1]);
        for (int i=1;i<=n+2;i++) pos[i]=i;
        build(1,n+2,0);//建一颗树
        root=(n+3)>>1;
        tot=n+2;
        for (int i=1;i<=m;i++) {
            string s;
            int x,y,len;
            cin>>s;
            if (s!="MAX-SUM") scanf("%d%d",&x,&len);
            else printf("%d
    ",t[root].middle);
            
            if (s=="INSERT") ins(x,len);//从x开始插入一个长度为len区间 
            if (s=="DELETE") del(x,len);//从x开始删除一个长度为len的区间 
            if (s=="MAKE-SAME") scanf("%d",&y),update(x,len,y);//从x开始把长度为len的区间连续修改成y 
            if (s=="REVERSE") reverse(x,len);//翻转从x开始长度为len的区间 
            if (s=="GET-SUM") query(x,len);//查询从x开始长度为len的区间和 
        } 
    }
  • 相关阅读:
    读操作
    读锁与写锁
    Mvcc
    readView
    版本链
    事务的隔离性
    索引的代价
    keras backend的修改
    caffe 笔记
    菜品识别 SDK调用
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13436873.html
Copyright © 2020-2023  润新知