bzoj1500: [NOI2005]维修数列

splay.

就是splay,没别的了。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 600000 + 10;
const int inf = 0x3f3f3f3f;

struct Splay {
    int v[maxn],s[maxn],sum[maxn];
    int l[maxn],r[maxn],f[maxn];
    int maxl[maxn],maxr[maxn],maxs[maxn];
    int same[maxn],rev[maxn];
    int q[maxn+1000],h,t;
    int root;

    int newnode() {
        int x=q[h++];
        if(h==maxn) h=0;
        return x;
    }

    void recycle(int x) {
        if(x==0) return;
        recycle(l[x]);
        recycle(r[x]);
        q[t++]=x;
        if(t==maxn) t=0;
    }

    void reverse(int x) {
        swap(l[x],r[x]);
        swap(maxl[x],maxr[x]);
        rev[x]^=1;
    }

    void make_same(int x,int val) {
        same[x]=v[x]=val;
        sum[x]=s[x]*val;
        if(val>0) maxl[x]=maxr[x]=maxs[x]=sum[x];
        else {maxl[x]=maxr[x]=0; maxs[x]=val;}
    }

    void push(int x) {
        if(same[x]!=inf) {
            make_same(l[x],same[x]);
            make_same(r[x],same[x]);
            same[x]=inf;
            if(rev[x]) rev[x]=0;
        }
        if(rev[x]) {
            reverse(l[x]);
            reverse(r[x]);
            rev[x]=0;
        }
    }

    void update(int x) {
        sum[x]=sum[l[x]]+sum[r[x]]+v[x];
        maxl[x]=max(maxl[l[x]],sum[l[x]]+v[x]+maxl[r[x]]);
        maxr[x]=max(maxr[r[x]],sum[r[x]]+v[x]+maxr[l[x]]);
        maxs[x]=max(max(maxs[l[x]],maxs[r[x]]),maxr[l[x]]+v[x]+maxl[r[x]]);
        s[x]=s[l[x]]+s[r[x]]+1;
    }

    void lr(int x) {
        int y=f[x];
        r[y]=l[x];
        if(l[x]) f[l[x]]=y;
        f[x]=f[y];
        if(root==y) root=x;
        else if(l[f[y]]==y) l[f[y]]=x;
        else r[f[y]]=x;
        f[y]=x; l[x]=y;
        update(y);
        update(x);
    }

    void rr(int x) {
        int y=f[x];
        l[y]=r[x];
        if(r[x]) f[r[x]]=y;
        f[x]=f[y];
        if(root==y) root=x;
        else if(l[f[y]]==y) l[f[y]]=x;
        else r[f[y]]=x;
        f[y]=x; r[x]=y;
        update(y);
        update(x);
    }

    void rotate(int x) {
        if(l[f[x]]==x) rr(x);
        else lr(x);
    }

    void splay(int x,int target=0) {
        while(f[x]!=target) {
            if(f[f[x]]==target) rotate(x);
            else if((l[f[x]]==x)==(l[f[f[x]]]==f[x])) {rotate(f[x]); rotate(x);}
            else {rotate(x); rotate(x);}
        }
    }

    int find(int k) {
        int x=root;
        push(x);
        while(k!=s[l[x]]+1) {
            if(k>s[l[x]]+1) {k-=s[l[x]]+1; x=r[x];}
            else x=l[x];
            push(x);
        }
        return x;
    }

    void Insert(int pos,int tot) {
        splay(find(pos+1),0);
        splay(find(pos+2),root);
        build(l[r[root]],r[root],1,tot);
        update(r[root]);
        update(root);
    }

    void Delete(int pos,int tot) {
        splay(find(pos),0);
        splay(find(pos+tot+1),root);
        recycle(l[r[root]]);
        l[r[root]]=0;
        update(r[root]);
        update(root);
    }

    void Make(int pos,int tot,int val) {
        splay(find(pos),0);
        splay(find(pos+tot+1),root);
        make_same(l[r[root]],val);
        update(r[root]);
        update(root);
    }

    void Reverse(int pos,int tot) {
        splay(find(pos),0);
        splay(find(pos+tot+1),root);
        reverse(l[r[root]]);
        update(r[root]);
        update(root);
    }

    int Get_sum(int pos,int tot) {
        splay(find(pos),0);
        splay(find(pos+tot+1),root);
        return sum[l[r[root]]];
    }

    int Max_sum() {
        return maxs[root];
    }

    void build(int &x,int fa,int L,int R) {
        if(L>R) {x=0; return;}
        x=newnode(); f[x]=fa; same[x]=inf; rev[x]=0;
        int mid=(L+R)/2;
        build(l[x],x,L,mid-1);
        scanf("%d",&v[x]);
        build(r[x],x,mid+1,R);
        update(x);
    }

    void init(int n) {
        v[0]=v[1]=v[2]=maxs[0]=-inf;
        same[1]=same[2]=inf;
        r[1]=2; f[2]=1; s[1]=2; s[2]=1;
        root=1;
        update(2); update(1);
        for(int i=3;i<maxn;i++) q[t++]=i;

        build(l[r[root]],r[root],1,n);
        update(r[root]);
        update(root);
    }

    /*void debug(int x) {
        if(!x) return;
        //push(x);
        debug(l[x]);
        printf("%d ",v[x]);
        debug(r[x]);
    }*/
}splay;

char op[20];
int n,m,val,tot,pos;

int main() {
    scanf("%d%d",&n,&m);
    splay.init(n);

    while(m--) {
        //splay.debug(splay.root);
        scanf("%s",op);
        if(op[0]==‘I‘) {
            scanf("%d%d",&pos,&tot);
            splay.Insert(pos,tot);
        }
        else if(op[0]==‘D‘) {
            scanf("%d%d",&pos,&tot);
            splay.Delete(pos,tot);
        }
        else if(op[0]==‘M‘ && op[2]==‘K‘) {
            scanf("%d%d%d",&pos,&tot,&val);
            splay.Make(pos,tot,val);
        }
        else if(op[0]==‘R‘) {
            scanf("%d%d",&pos,&tot);
            splay.Reverse(pos,tot);
        }
        else if(op[0]==‘G‘) {
            scanf("%d%d",&pos,&tot);
            printf("%d\n",splay.Get_sum(pos,tot));
        }
        else {
            printf("%d\n",splay.Max_sum());
        }
    }
    return 0;
}
时间: 2025-01-02 00:18:38

bzoj1500: [NOI2005]维修数列的相关文章

BZOJ1500: [NOI2005]维修数列[splay ***]

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12278  Solved: 3880[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

[bzoj1500][NOI2005 维修数列] (splay区间操作)

Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格. 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内. 插入的数字总数不超过4 000 000个,输入文件大小不超过20MBytes. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次

BZOJ1500 NOI2005 维修数列 平衡树

题意:给定一个数列,要求维护:1.在p之后加入tot个数  2.删除p之后tot个数  3.将p之后tot个数修改为c  4.翻转p之后tot个数  5.输出p之后tot个数的和  6.输出整个数列的最大子段和. 题解:平衡树很经典的题目了……主要说一下4和6操作,4的话因为翻转操作是可以分治的,所以可以用翻转标记:6我们维护一个节点所维护的区间的的最大子段和ms.从左开始的最大子段和lms.从右开始的最大子段和rms,显然有ms=max(lchild->ms,rchild->ms,lchil

1500: [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12952  Solved: 4138[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

BZOJ 1500: [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 12880  Solved: 4112[Submit][Status][Discuss] Description Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格.任何时刻数列中最多含有500 000个数,

[NOI2005] 维修数列

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

Splay必做题 [NOI2005]维修数列

1500: [NOI2005]维修数列 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 6577  Solved: 1978[Submit][Status] Description Input 输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目.第2行包含N个数字,描述初始时的数列.以下M行,每行一条命令,格式参见问题描述中的表格. Output 对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印

BZOJ 1500: [NOI2005]维修数列( splay )

splay..... ------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #define rep( i , n ) for( int i = 0 ; i < n ; ++

【BZOJ】1500: [NOI2005]维修数列

[算法]splay [题解]数据结构 感谢Occult的模板>_<:HYSBZ 1500 维修数列 #include<cstdio> #include<cctype> #include<cstring> #include<queue> #include<algorithm> using namespace std; const int maxn=5e5+10,inf=0x3f3f3f3f; int n,m,root,a[maxn],t