题目大意,给n个点表示n个村庄,一开始都是相连的,现在有3种操作:Q x,查询第与第x个村庄相连的村庄个数;D x,摧毁掉第x个村庄;R 恢复刚摧毁的村庄。
题目分析:每个点用2个状态表示,0表示被摧毁,1表示存在,因为有恢复操作,并且每次恢复上一个被摧毁的村庄,所以用一个栈存储所有被摧毁的村庄,每次R操作恢复栈顶村庄。这题关键是查询操作,如果查询的村庄x不存在,则没有村庄与之相连通,如果存在x村庄,那么从x往2边找连续的存在的村庄。如何找这个连续的存在的村庄。
自顶向下找,如果找到左边第一个不存在的村庄,找到右边第一个不存在的村庄,相减即可。
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 50005
#define lson rt<<1 , l , m
#define rson rt<<1|1 , m+1 , r
int tree[maxn<<2],leaf[maxn],n;
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt]=1;
leaf[l]=rt;
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void update(int rt,int l,int r,int x,int val)
{
if(l==r)
{
tree[rt]=val;
return ;
}
int m=(l+r)>>1;
if(x<=m)
update(lson,x,val);
else
update(rson,x,val);
if(tree[rt<<1]==(m-l+1)&&tree[rt<<1|1]==r-m)
tree[rt]=r-l+1;
else
tree[rt]=0;
}
int query(int rt,int l,int r,int x,int dir)
{
int m=(l+r)>>1;
if(x<1||x>n)
{
return x;
}
if(tree[rt]==r-l+1)
{
if(dir)
{
return query(1,1,n,r+1,dir);
}
else
{
return query(1,1,n,l-1,dir);
}
}
if(l==r)
{
return l;
}
if(x<=m)
return query(lson,x,dir);
else
return query(rson,x,dir);
}
int main()
{
char op[5];
int m,a,b,c,x,y,z;
while(~scanf("%d%d",&n,&m))
{
stackst;
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='R')
{
int num=st.top();
st.pop();
update(1,1,n,num,1);
}
else
{
scanf("%d",&x);
if(op[0]=='D')
{
st.push(x);
update(1,1,n,x,0);
}
else
{
int ans = tree[leaf[x]];
if(ans == 0)
printf("0\n");
else
{
ans=1;
if(x1)
{
ans+=x-query(1,1,n,x-1,0)-1;
}
printf("%d\n",ans);
}
}
}
}
}
return 0;
}
SBT版,比poj多了一个坑点,就是同一个城市可以删多次,对于线段树无所谓,可对于SBT来说会造成多个相同值的插入。
#include
#include
#include
#include
#include
#include
using namespace std;
#define maxn 510000
int n,m,l,r,root,cnt,val[maxn],ls[maxn],rs[maxn],siz[maxn];
bool vis[maxn];
void rotate_r(int &x)
{
int y=ls[x];
siz[y]=siz[x];
ls[x]=rs[y];
rs[y]=x;
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
x=y;
}
void rotate_l(int &x)
{
int y=rs[x];
siz[y]=siz[x];
rs[x]=ls[y];
ls[y]=x;
siz[x]=siz[ls[x]]+siz[rs[x]]+1;
x=y;
}
void maintain(int& x,int fg)
{
if(!fg)
{
if(siz[ls[ls[x]]]>siz[rs[x]]) rotate_r(x);
else if(siz[rs[ls[x]]]>siz[rs[x]]) rotate_l(ls[x]),rotate_r(x);
else return ;
}
else
{
if(siz[rs[rs[x]]]>siz[ls[x]]) rotate_l(x);
else if(siz[ls[rs[x]]]>siz[ls[x]]) rotate_r(rs[x]),rotate_l(x);
else return ;
}
maintain(ls[x],0);maintain(rs[x],1);
maintain(x,0);maintain(x,1);
}
void insert(int& x,int b)
{
if(!x)
{
cnt++;
x=cnt;
ls[x]=rs[x]=0;
siz[x]=1;
val[x]=b;
}
else
{
siz[x]++;
if(b>val[x]) insert(rs[x],b);
else insert(ls[x],b);
maintain(x,b>=val[x]);
}
}
int delt(int& x,int b)
{
siz[x]--;
if(b==val[x]||(bval[x]&&rs[x]==0))
{
int y=val[x];
if(!ls[x]||!rs[x]) x=ls[x]+rs[x];
else val[x]=delt(ls[x],b+1);
return y;
}
else
{
if(bb) return succ(ls[x],x,b);
return succ(rs[x],y,b);
}
void sbt()
{
root=cnt=0;
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(siz,0,sizeof(siz));
memset(vis,0,sizeof(vis));
memset(val,0,sizeof(val));
insert(root,0);
insert(root,n+1);
int op,a,b,f;
char str[10];
stackst;
for(int i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='D')
{
scanf("%d",&b);
if(!vis[b]) insert(root,b);
st.push(b);
vis[b]=true;
}
else if(str[0]=='Q')
{
scanf("%d",&b);
if(vis[b])
{
printf("0\n");
continue;
}
int f1=pred(root,0,b);
int f2=succ(root,0,b);
printf("%d\n",val[f2]-val[f1]-1);
}
else
{
delt(root,st.top());
vis[st.top()]=false;
st.pop();
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
sbt();
}
return 0;
}