hdu4441 splay

题意:给定一个序列 然后要求维护一个序列 使得这个序列是一个合法的队列结构 然后询问操作是对于+i -i之间的和是多少  删除操作 在原定序列中删除+i 和-i  插入操作插入+i的位置 然后-i的位置是最右边的合法位置

解法:直接上splay就可以了 不过调整了比较久的时间 实际上这三个操作都不是很难 

#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define ls ch[rt][0]
#define rs ch[rt][1]
#define rrs ch[root][1]
#define rls ch[root][0]
#define maxn 222222
int ch[maxn][2],fa[maxn],num[maxn],pos[maxn],neg[maxn],val[maxn];
ll sum[maxn];
int root,clc;
void up(int rt){
	sum[rt]=val[rt];num[rt]=1;
	pos[rt]=(val[rt]>0);
	neg[rt]=(val[rt]<=0);
    for(int i=0;i<2;++i){
		int son=ch[rt][i];
		if(!son)continue;
    sum[rt]+=sum[son],num[rt]+=num[son],pos[rt]+=pos[son],neg[rt]+=neg[son];
	}
}
inline 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);
}
inline void splay(int rt,int aim){
    while(fa[rt]!=aim){
        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;
}
inline void find(int tot,int sub){
    int rt=sub;
    while(1){
        if(tot==num[ls]+1)break;
        if(num[ls]>=tot)rt=ls;
        else tot-=num[ls]+1,rt=rs;
    }
    splay(rt,fa[sub]);
}
inline int count(int posi){
    int res=0,rt=root;
    while(rt!=0){
        int cnt=(ls==0?(val[rt]<=0):(val[rt]<=0)+neg[ls]);
        if(posi<cnt)rt=ls;
        else posi-=cnt,res+=(ls==0?1:1+num[ls]),rt=rs;
    }return res;
}
set<int>se;
int l[maxn],r[maxn],m,k,_=0;
char op[111];
inline void init(){
    ch[2][0]=ch[2][1]=ch[1][1]=0;ch[1][0]=2;
    fa[2]=1;fa[1]=0;val[1]=val[2]=0;up(2),up(1);
    val[0]=num[0]=0;
    root=1,clc=2;
}
int main(){
	while(~scanf("%d",&m)){
		printf("Case #%d:\n",++_);
		se.clear();
		for(int i=1;i<=100000;++i){se.insert(i);l[i]=r[i]=-1;}
        init();
		while(m--){
			scanf("%s %d",op,&k);
			if(*op=='i'){
                int w=(*(se.begin()));se.erase(w);
                
                find(k+1,root);
                find(1,rrs);
                ch[rrs][0]=++clc;
				val[clc]=w;ch[clc][0]=ch[clc][1]=0,fa[clc]=rrs;
				up(clc);splay(clc,0);
				l[w]=clc;
                
                int cnt=count(pos[ch[clc][0]]+1);
                find(cnt,root);
                find(1,rrs);
				ch[rrs][0]=++clc;
				val[clc]=-w;
				ch[clc][0]=ch[clc][1]=0;
				fa[clc]=rrs;up(clc);
				splay(clc,0);
				r[w]=clc;
			}
			else if(*op=='q'){
				splay(l[k],0);
				splay(r[k],root);
				ll ans=(ch[r[k]][0]==0?0:sum[ch[r[k]][0]]);
				printf("%I64d\n",ans);
			}
			else if(*op=='r'){
				splay(l[k],0);
				int cnt=num[rls];
                find(cnt,root),find(2,rrs);ch[rrs][0]=0;
                up(rrs),up(root);
                
				splay(r[k],0);
                cnt=num[rls];
                find(cnt,root),find(2,rrs);ch[rrs][0]=0;
                up(rrs),up(root);
                
				se.insert(k);
				l[k]=r[k]=-1;
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值