hdu 3436 splay模拟题

http://acm.hdu.edu.cn/showproblem.php?pid=3436

离线操作,将两个数之间那段数的个数也当做一个节点放在伸展树中,找的时候根据节点的个数往左或往右找就好了

/*
关键是离散化的技巧
其他没什么
*/
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<algorithm>
using namespace std;
const int inf  = ~0u>>2;
#define L ch[x][0]
#define R ch[x][1]
#define KT (ch[ ch[rt][1] ][0])
const int maxn = 200010;
struct SplayTree {
    int sz[maxn];
    int ch[maxn][2];
    int pre[maxn];
    int rt,top;
    inline void up(int x){
        sz[x]  = s[x] + sz[ L ] + sz[ R ];
    }
    inline void Rotate(int x,int f){
        int y=pre[x];
        ch[y][!f] = ch[x][f];
        pre[ ch[x][f] ] = y;
        pre[x] = pre[y];
        if(pre[x]) ch[ pre[y] ][ ch[pre[y]][1] == y ] =x;
        ch[x][f] = y;
        pre[y] = x;
        up(y);
    }
    inline void Splay(int x,int goal){//将x旋转到goal的下面
        while(pre[x] != goal){
            if(pre[pre[x]] == goal) Rotate(x , ch[pre[x]][0] == x);
            else   {
                int y=pre[x],z=pre[y];
                int f = (ch[z][0]==y);
                if(ch[y][f] == x) Rotate(x,!f),Rotate(x,f);
                else Rotate(y,f),Rotate(x,f);
            }
        }
        up(x);
        if(goal==0) rt=x;
    }
    inline void RTO(int k,int goal){//将第k位数旋转到goal的下面
        int x=rt;
        while(sz[ L ] != k-1) {
            if(k < sz[ L ]+1) x=L;
            else {
                k-=(sz[ L ]+1);
                x = R;
            }
        }
        Splay(x,goal);
    }
    inline void vist(int x){
        if(x){
            printf("结点%2d : 左儿子  %2d   右儿子  %2d   %2d sz=%d\n",x,L,R,mp[x],sz[x]);
            vist(L);
            vist(R);
        }
	}
    void Del(){
	     int t=rt;
		 if(ch[rt][1]) {
			 rt=ch[rt][1];
			 RTO(1,0);
			 ch[rt][0]=ch[t][0];
			 if(ch[rt][0]) pre[ch[rt][0]]=rt;
		 }
		 else rt=ch[rt][0];
		 pre[rt]=0;
		 up(rt);
	}
    inline void Newnode(int &x,int id,int f){
        x=++top;
        L = R = 0;
		pre[x] = f;
        sz[x]=s[x]=ed[id]-bg[id]+1; 
        mp[x]=id;
		node[id]=x;
    }
	void build(int &x,int l,int r,int f){
		if(l>r) return ;
		int m=l+r>>1;
		Newnode(x,m,f);
		build(L,l,m-1,x);
		build(R,m+1,r,x);
		pre[x]=f;
		up(x);
	}
    void init(){
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        rt=top=0;
		scanf("%d%d",&n,&m);
		tot=0;
		int k=0;
		num[k++]=1;
        for(int i=1;i<=m;i++){
			scanf("%s%d",op[i],&x[i]);
			if(op[i][0]=='T' || op[i][0]=='Q') 		num[k++]=x[i];
			
		}
		num[k++]=n;
		sort(num,num+k);
		bg[tot]=num[0];
		ed[tot++]=num[0];
		for(int i=1;i<k;i++){
			if(num[i]!=num[i-1]){
				if(num[i-1]+1<num[i]) {
					bg[tot]=num[i-1]+1;
					ed[tot++]=num[i]-1;
				}
				bg[tot]=num[i];
				ed[tot++]=num[i];
			}
		}
		build(rt,0,tot-1,0);
    }
	void Insert(int &x,int id,int p){
		if(x==0) {
			Newnode(x,id,p);
			Splay(x,0);
			return ;
		}
		Insert(L,id,x);
		up(x);
	}
	void Query(int xx){
		int id=lower_bound(bg,bg+tot,xx)-bg;
		Splay(node[id],0);;
		printf("%d\n",sz[ch[rt][0]]+1);
	}
	void Top(int xx) {
		int id=lower_bound(bg,bg+tot,xx)-bg;
		Splay(node[id],0);
		Del();
		Insert(rt,id,0);
		Splay(node[id],0);
	}
	int Find(int x,int xx){
		int id=mp[x];
		if(xx <= sz[ L ]) 
			return Find(L,xx);
		else if(xx <= sz[ L ] + s[x])
			return bg[id] + (xx-sz[ L ]) -1;
		else 
			return Find(R,xx - sz[ L ] - s[x]);
	}
	void solve()	{
		for(int i=1;i<=m;i++) {
			if(op[i][0]=='T') {
				Top(x[i]);
			} else if(op[i][0]=='Q'){
				Query(x[i]);
			}  else {
				printf("%d\n",Find(rt,x[i]));
			}
		}
	}
    int bg[maxn];
	int ed[maxn];
	int num[maxn];
	int s[maxn];
	int mp[maxn];
	int x[maxn];
	int node[maxn];
	int n,m,tot;
	char op[maxn][6];
}spt;
int main(){
	int t,ca=1;
	scanf("%d",&t);
	while(t--) {
		printf("Case %d:\n",ca++);
		spt.init();
		spt.solve();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值