bzoj1895: Pku3580 supermemo

传送门
发现题目中的所有东西都可以用splay维护
然后就理所应当的成了splay裸题了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#define N 300030
using namespace std;
int n,m,x,y,d,t,p,rt,cnt;
int a[N],f[N],ch[N][2],sz[N],mn[N],key[N],add[N],rev[N];
char s[20];
void clear(int x){
    f[x]=ch[x][0]=ch[x][1]=sz[x]=0;
    mn[x]=key[x]=add[x]=rev[x]=0;
}
int get(int x){
    return ch[f[x]][1]==x;
}
void update(int x){
    sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
    mn[x]=key[x];
    if (ch[x][0]) mn[x]=min(mn[x],mn[ch[x][0]]);
    if (ch[x][1]) mn[x]=min(mn[x],mn[ch[x][1]]);
}
void pushdown(int x){
    if (!x) return;
    if (rev[x]){
        rev[ch[x][0]]^=1;
        rev[ch[x][1]]^=1;
        swap(ch[x][0],ch[x][1]);
        rev[x]=0;
    }
    if (add[x]){
        add[ch[x][0]]+=add[x],add[ch[x][1]]+=add[x];
        key[ch[x][0]]+=add[x],key[ch[x][1]]+=add[x];
        mn[ch[x][0]]+=add[x],mn[ch[x][1]]+=add[x];
        add[x]=0;
    }
}
int build(int l,int r,int fa){
    if (l>r) return 0;
    int mid=(l+r)/2,x=++cnt;
    f[x]=fa; key[x]=a[mid];
    ch[x][0]=build(l,mid-1,x);
    ch[x][1]=build(mid+1,r,x);
    update(x);
    return x;
}
void rotate(int x){
    pushdown(f[x]); pushdown(x);
    int y=f[x],z=f[y],l=get(x),r=l^1;
    if (z) ch[z][get(y)]=x;
    f[x]=z; f[y]=x; f[ch[x][r]]=y;
    ch[y][l]=ch[x][r]; ch[x][r]=y;
    update(y); update(x);
}
void splay(int x,int tar){
    for (;f[x]!=tar;rotate(x))
        if (f[f[x]]!=tar)
            rotate(get(x)==get(f[x])?f[x]:x);
    if (!tar) rt=x;
}
int find(int rk){
    int x=rt;
    while(1){
        pushdown(x);
        if (rk<=sz[ch[x][0]]) x=ch[x][0];
        else{
            rk-=sz[ch[x][0]]+1;
            if (!rk) return x;
            x=ch[x][1];
        }
    }
}
void pre(int x,int y){
    int a=find(x),b=find(y);
    splay(a,0); splay(b,a);
}
void up(){
    update(ch[rt][1]);
    update(rt);
}
int main(){
    scanf("%d",&n);
    a[1]=2e9; a[n+2]=-2e9;
    for (int i=2;i<=n+1;i++) scanf("%d",&a[i]);
    rt=build(1,n+2,0);
    scanf("%d",&m);
    while (m--){
        scanf("%s",s);
        if (s[0]=='A'){
            scanf("%d%d%d",&x,&y,&d);
            if (x>y) swap(x,y);
            pre(x,y+2);
            mn[ch[ch[rt][1]][0]]+=d;
            add[ch[ch[rt][1]][0]]+=d;
            key[ch[ch[rt][1]][0]]+=d;
            up();
        }
        else if (s[0]=='I'){
            scanf("%d%d",&x,&p);
            pre(x+1,x+2);
            ch[ch[rt][1]][0]=++cnt;
            f[cnt]=ch[rt][1];
            key[cnt]=mn[cnt]=p;
            sz[cnt]=1;
            up();
        }
        else if (s[0]=='D'){
            scanf("%d",&x);
            pre(x,x+2);
            int del=ch[ch[rt][1]][0];
            clear(del);
            ch[ch[rt][1]][0]=0;
            up(); 
        }
        else if (s[0]=='M'){
            scanf("%d%d",&x,&y);
            if (x>y) swap(x,y);
            pre(x,y+2);
            printf("%d\n",mn[ch[ch[rt][1]][0]]);
        }
        else if (s[3]=='E'){
            scanf("%d%d",&x,&y);
            if (x==y) continue;
            pre(x,y+2);
            rev[ch[ch[rt][1]][0]]^=1;
        }
        else{
            scanf("%d%d%d",&x,&y,&t);
            if (x>y) swap(x,y);
            t%=(y-x+1);
            if (!t) continue;
            pre(y-t+1,y+2);
            int now=ch[ch[rt][1]][0];
            ch[ch[rt][1]][0]=0;
            up();
            pre(x,x+1);
            ch[ch[rt][1]][0]=now;
            f[now]=ch[rt][1];
            up();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值