POJ2892 HDU1540 Tunnel Warfare(Splay)

有n个村庄连成一排,m个指令。D x为破坏村庄x,Q x为查询与x联通的村庄的个数,R为恢复上一个被破坏的村庄。

用一棵splay树,每次破坏一个村庄,就插入它的编号;查询的时候找到前驱后继(当然,如果该村庄已经被破坏,直接输出0就好了);恢复村庄时再删除这个节点。注意为了方便查询,我们先插入0和n+1。

#include<cstdio>
#include<cctype>
#include<stack>
#define MAXN 50010
using namespace std;
int n,m,fa[MAXN],ch[MAXN][2],v[MAXN],root,cnt,num;
stack<int> S;
char ops[3];
bool instack[MAXN];
void rotate(int x)
{
	int y = fa[x],z = fa[y],f = (ch[y][1]==x);
	ch[y][f] = ch[x][!f];
	if(ch[y][f]) fa[ch[y][f]] = y;
	ch[x][!f] = y,fa[y] = x;
	fa[x] = z;
	if(z) ch[z][ch[z][1]==y] = x;
}
void splay(int x,int goal)
{
	for(int y; (y=fa[x])!=goal; rotate(x))
	{
		int z = fa[y];
		if(z != goal)
		{
			if((ch[z][1]==y)==(ch[y][1]==x)) rotate(y);
			else rotate(x);
		}
	}
	if(goal == 0) root = x;
}
void insert(int val)
{
	int x = root,y = 0,f = 0;
	while(x != 0)
	{
		if(v[x] == val) break;
		f = (v[x]<val);
		y = x;
		x = ch[x][f];
	}
	if(x == 0) 
	{	
		x = ++cnt;
		v[x] = val;
		fa[x] = y;
		if(y) ch[y][f] = x;
	}
	splay(x,0);
}
int nxt(int val,bool flag)
{
	int x = root,y = 0;
	while(x != 0)
	{
		y = x;
		if(v[x] == val) break;
		x = ch[x][v[x]<val];
	}
	if((v[y]>val&&flag==1)||(v[y]<val&&flag==0)) return y;
	splay(y,0);
	int tmp = ch[y][flag];
	while(ch[tmp][!flag])
		tmp = ch[tmp][!flag];
	return tmp;
}
void del(int val)
{
	int x = nxt(val,0),y = nxt(val,1);
	splay(x,0);
	splay(y,x);
	int z = ch[y][0];
	if(z)
	{
		ch[y][0] = 0;
		splay(y,0);
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	insert(0);
	insert(n+1);
	while(m--)
	{
		scanf("%s",ops);
		if(ops[0] == 'D')
		{
			scanf("%d",&num);
			insert(num);
			S.push(num);
			instack[num] = 1;
		}
		else if(ops[0] == 'Q')
		{
			scanf("%d",&num);
			if(instack[num]) printf("0\n");
			else
			{	
				int x = v[nxt(num,0)],y = v[nxt(num,1)];
				printf("%d\n",y-x-1);
			}
		}
		else 
		{
			if(!S.empty())
			{
				del(S.top());
				instack[S.top()] = 0;
				S.pop();
			}
		}
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值