hdu4453 Splay

题意:题目的意思很明显了 这个基本上就是要靠树来维护圆环的点删除 点循环 点询问 和区间翻转 区间加法

解法:直接无脑splay就可以了 这题基本上写出来没什么问题 就是调试需要一些方法的 我是这么调试的

用move 1 query循环一遍 然后再用move 2循环一遍 其他的直接无脑调试就可以了 

复杂度大概是不能多说 不过常数不是很大 如果想小一点的话尽量少用几个find就可以了

#include<cstdio>
#include<iostream>
using namespace std;
#define maxn 222222
#define ls ch[rt][0]
#define rs ch[rt][1]
#define rrs ch[root][1]
#define rls ch[root][0]
int n,m,k1,k2,x;
char op[111];
int ch[maxn][2],fa[maxn],val[maxn],num[maxn],root,rev[maxn],add[maxn],cnt;
void node(int rt){ls=rs=fa[rt]=rev[rt]=add[rt]=val[rt]=0;num[rt]=1;}
void up(int rt){num[rt]=num[ls]+num[rs]+1;}
void down(int rt){
    if(rev[rt]){
        rev[ls]^=1;rev[rs]^=1;
        swap(ls,rs);rev[rt]=0;
    }if(add[rt]){
        add[ls]+=add[rt];add[rs]+=add[rt];
        val[ls]+=add[rt];val[rs]+=add[rt];
        add[rt]=0;
    }
}
void rot(int rt){
    int f=fa[rt],side=ch[f][1]==rt,ll=ch[rt][!side];
    fa[ll]=f,ch[f][side]=ll;
    fa[rt]=fa[f],ch[fa[f]][ch[fa[f]][1]==f]=rt;
    fa[f]=rt;ch[rt][!side]=f;
    up(f),up(rt);
}
void splay(int rt,int aim){
    while(fa[rt]!=aim){
        down(rt);
        int f=fa[rt],ff=fa[f];
        if(ff==aim)rot(rt);
        if((ch[f][1]==rt)==(ch[ff][1]==f))rot(f),rot(rt);
        else rot(rt),rot(rt);
    }if(!aim)root=rt;
}
void find(int tot,int sub){
    int rt=sub;
    while(1){
        down(rt);
        if(num[ls]+1==tot)break;
        if(num[ls]>=tot)rt=ls;
        else tot-=num[ls]+1,rt=rs;
    }
    splay(rt,fa[sub]);
}

void query(){
    find(2,root);
    printf("%d\n",val[root]);
}
void _add(int x){
    find(1,root);
    find(k2+1,rrs);
    int rt=ch[rrs][0];
    if(rt)add[rt]+=x,val[rt]+=x;
}
void ins(int va){
    ++n;
    find(2,root),find(1,rrs);
    node(++cnt);ch[rrs][0]=cnt;fa[cnt]=rrs,val[cnt]=va;
    up(rrs),up(root);
}
void _rev(){
    find(1,root);
    find(k1+1,rrs);
    int rt=ch[rrs][0];
    if(rt)rev[rt]^=1;
}
int del(){
    find(1,root);
    find(2,rrs);int rt=ch[rrs][0];
    ch[rrs][0]=0;--n;
    up(rrs),up(root);
    return val[rt];
}
void mov(int x){
    if(x==1){
        find(n+1,root);int va=val[root];
        fa[rrs]=0,fa[rls]=rrs,ch[rrs][0]=rls;
        root=rrs;up(root);
        find(1,root);find(1,rrs);
        node(++cnt);
        val[cnt]=va;fa[cnt]=rrs;ch[rrs][0]=cnt;
        up(rrs),up(root);
    }else{
        int va=del();
        find(n+1,root);find(1,rrs);
        node(++cnt);fa[cnt]=rrs;val[cnt]=va;
        ch[rrs][0]=cnt;n++;
        up(rrs),up(root);
    }
}
int a[maxn];
void build(){
    node(0);num[0]=0;
    for(int i=1;i<=n+2;++i){node(i);}cnt=n+2;
    fa[n+2]=n+1;ch[n+1][1]=n+2;
    for(int i=1;i<=n+1;++i){fa[i]=i+1;ch[i+1][0]=i;val[i]=a[i];up(i);}
    fa[n+1]=0;root=n+1;
}int _=0;
int main(){
    while(~scanf("%d%d%d%d",&n,&m,&k1,&k2)){
        if(!n&&!m&&!k1&&!k2)break;printf("Case #%d:\n",++_);
        for(int i=2;i<=n+1;++i)scanf("%d",&a[i]);
        build();
        while(m--){
            scanf("%s",op);
            switch(*op){
                case'q':query();break;
                case'i':scanf("%d",&x);ins(x);break;
                case'a':scanf("%d",&x);_add(x);break;
                case'm':scanf("%d",&x);mov(x);break;
                case'd':del();break;
                case'r':_rev();break;
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值