有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();
}
}
}
}