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的区间和 
    } 
}
原文地址:https://www.cnblogs.com/zhanglichen/p/13436873.html