【bzoj1500】【NOI2005】维修数列

Description

维护一个数列,支持6种操作。
1:插入 在第pos个数后面插入tot个数
2:删除 删除第pos个数开始的tot个数
3:修改 将第pos个数开始的tot个数统一改成c
4:翻转 将第pos个数开始的tot个数翻转
5:求和 计算第pos个数开始的tot个数的和
6:最大和子序列 求这个序列的最大和子序列
100%的数据中,任何时刻数列中最多含有500 000个数。
100%的数据中,任何时刻数列中任何一个数字均在[-1 000, 1 000]内。
100%的数据中,操作数≤2*10^4,插入的数字总数不超过4 *10^7个.

Solution

看到翻转神马的,splay直接上。
考验码力的时候到了。
某神犇:把这道题拎出来,在一个小时内切掉,你以后splay都可以随脑打了。
我只不过打了2.5h而已(带垃圾回收)。。。(果然splay还是无法像segmenttree一样)
上bzoj交了一发,5504ms,(⊙v⊙)嗯,看看排第几?
!!!第一那个1316ms是怎么回事(⊙_⊙?)
我在哪?
。。。。
。。。。
。。。。
。。。。
620,好数字~(>_<)~
图样图森破

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 500005
using namespace std;
const int Mx=1005;
int t[N][2],f[N],a[N],d[N],stack[N],rev[N],same[N],key[N],n,m,z,root,tot,pos,cnt;
char s[25];
struct note{
    int son[2],lmax,rmax,sum,max,size;
}tr[N];
int newnode(int x) {
    int id;
    if (d[0]) id=d[d[0]--];else id=++cnt;tr[id].size=1;same[id]=Mx;
    key[id]=tr[id].sum=tr[id].max=x;tr[id].lmax=tr[id].rmax=max(x,0);
    rev[id]=f[id]=t[id][0]=t[id][1]=0;
    return id;
}
void updata(int x) {
    if (!x) return;
    int l=t[x][0],r=t[x][1];
    tr[x].size=tr[l].size+tr[r].size+1;
    tr[x].sum=tr[l].sum+tr[r].sum+key[x];
    tr[x].lmax=max(tr[l].lmax,tr[l].sum+key[x]+tr[r].lmax);
    tr[x].rmax=max(tr[r].rmax,tr[r].sum+key[x]+tr[l].rmax);
    tr[x].max=max(tr[l].max,max(tr[r].max,tr[l].rmax+key[x]+tr[r].lmax));
}
void makesame(int x,int y) {
    if (!x) return;
    tr[x].sum=y*tr[x].size;
    key[x]=y;same[x]=y;
    if (y>0) tr[x].lmax=tr[x].rmax=tr[x].max=tr[x].sum;
    else tr[x].lmax=tr[x].rmax=0,tr[x].max=y;
}
void reverse(int x) {
    if (!x) return;
    swap(t[x][0],t[x][1]);
    swap(tr[x].lmax,tr[x].rmax);
    rev[x]^=1;
}
void down(int x) {
    if (!x) return;
    if (same[x]!=Mx) {
        makesame(t[x][0],same[x]);
        makesame(t[x][1],same[x]);
        same[x]=Mx;
    }
    if (rev[x]) {
        reverse(t[x][0]);
        reverse(t[x][1]);
        rev[x]=0;
    }
}
void remove(int x,int y) {
    do {
        stack[++stack[0]]=x;x=f[x];
    } while (x!=y);
    while (stack[0]) down(stack[stack[0]--]);
}
int build(int l,int r,int fa) {
    if (l>r) return 0;
    int m=(l+r)/2,x=newnode(a[m]);
    f[x]=fa;
    if (l==r) return x;
    t[x][0]=build(l,m-1,x);
    t[x][1]=build(m+1,r,x);
    updata(x);return x;
}
int get_id(int x,int id) {
    down(x);
    if (tr[t[x][0]].size+1==id) return x;
    if (tr[t[x][0]].size+1>id) return get_id(t[x][0],id);
    else return get_id(t[x][1],id-tr[t[x][0]].size-1);
}
int son(int x) {
    if (x==t[f[x]][0]) return 0;else return 1;
}
void rotate(int x) {
    int y=f[x],z=son(x);f[x]=f[y];
    if (f[x]) t[f[x]][son(y)]=x;
    if (t[x][1-z]) f[t[x][1-z]]=y;
    f[y]=x;t[y][z]=t[x][1-z];t[x][1-z]=y;
    updata(y);updata(x);
}
void splay(int x,int y) {
    if (x==y) return;
    remove(x,y);
    while (f[x]!=y) {
        if (f[f[x]]!=y)
            if (son(x)==son(f[x])) rotate(f[x]);
            else rotate(x);
        rotate(x);
    }
    if (!y) root=x;
}
void del(int x) {
    if (!x) return;d[++d[0]]=x;
    del(t[x][0]);del(t[x][1]);
}
int main() {
    scanf("%d%d",&n,&m);tr[0].max=-0x7fffffff;
    fo(i,1,n) scanf("%d",&a[i]);
    root=build(0,n+1,0);
    for(;m;m--) {
        scanf("%s",s);
        if (s[0]=='I') {
            scanf("%d%d",&pos,&tot);pos++;
            fo(i,1,tot) scanf("%d",&a[i]);
            int x=get_id(root,pos);splay(x,0);
            int y=get_id(root,pos+1);splay(y,x);
            t[y][0]=build(1,tot,y);updata(y);updata(x);
        }
        if (s[0]=='D') {
            scanf("%d%d",&pos,&tot);pos++;
            int x=get_id(root,pos-1);splay(x,0);
            int y=get_id(root,pos+tot);splay(y,x);
            del(t[y][0]);t[y][0]=0;updata(y);updata(x);
        }
        if (s[2]=='K') {
            scanf("%d%d%d",&pos,&tot,&z);pos++;
            int x=get_id(root,pos-1);splay(x,0);
            int y=get_id(root,pos+tot);splay(y,x);
            makesame(t[y][0],z);updata(y);updata(x);
        }
        if (s[0]=='R') {
            scanf("%d%d",&pos,&tot);pos++;
            int x=get_id(root,pos-1);splay(x,0);
            int y=get_id(root,pos+tot);splay(y,x);
            reverse(t[y][0]);updata(y);updata(x);
        }
        if (s[0]=='G') {
            scanf("%d%d",&pos,&tot);pos++;
            int x=get_id(root,pos-1);splay(x,0);
            int y=get_id(root,pos+tot);splay(y,x);
            printf("%d\n",tr[t[y][0]].sum);
        }
        if (s[2]=='X') {
            int x=get_id(root,1);splay(x,0);
            int y=get_id(root,tr[root].size);splay(y,x);
            printf("%d\n",tr[t[y][0]].max);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值