我用的是treap操作的
每一次把被摧毁的村庄放进treap中,然后找到查询点的前驱和后继就是该联通块的起始点前一个和终止点后一个,之后每个联通块中村庄的个数也就知道了,每次修复时将这个村庄从treap中删除即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int n,m;
int s,t,sz,root;
int d[50005];
struct Tree
{
int l,r;
int num,rnd;
}tree[50005];
void lturn(int &t)
{
int k=tree[t].r;
tree[t].r=tree[k].l;
tree[k].l=t;
t=k;
}
void rturn(int &t)
{
int k=tree[t].l;
tree[t].l=tree[k].r;
tree[k].r=t;
t=k;
}
void del(int &w,int x)
{
if(tree[w].num==x)
{
if(tree[w].l*tree[w].r==0) w=tree[w].l+tree[w].r;
else if(tree[tree[w].l].rnd<tree[tree[w].r].rnd)
{
rturn(w);
del(w,x);
}
else if(tree[tree[w].l].rnd>=tree[tree[w].r].rnd)
{
lturn(w);
del(w,x);
}
return;
}
else if(tree[w].num<x) del(tree[w].r,x);
else del(tree[w].l,x);
}
void find(int &w,int x)
{
if(w==0) return;
if(tree[w].num>=x && tree[w].num<t) t=tree[w].num;
if(tree[w].num<=x && tree[w].num>s) s=tree[w].num;
if(tree[w].num<x) find(tree[w].r,x);
else find(tree[w].l,x);
}
void insert(int &w,int x)
{
if(w==0)
{
sz++;
w=sz;
tree[w].num=x;
tree[w].rnd=rand();
return;
}
if(tree[w].num<x)
{
insert(tree[w].r,x);
if(tree[tree[w].r].rnd<tree[w].rnd) lturn(w);
}
if(tree[w].num>x)
{
insert(tree[w].l,x);
if(tree[tree[w].l].rnd<tree[w].rnd) rturn(w);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,j=0;i<=m;i++)
{
char c;
int a;
getchar();
scanf("%c",&c);
if(c=='D')
{
scanf("%d",&a);
insert(root,a);
j++;
d[j]=a;
}
if(c=='Q')
{
scanf("%d",&a);
s=0;t=n+1;
find(root,a);
if(s==a&&t==a) printf("0\n");
else printf("%d\n",t-s-1);
}
if(c=='R')
{
del(root,d[j]);
j--;
}
}
return 0;
}

本文介绍了一种使用Treap数据结构解决村庄查询问题的方法。通过将被摧毁的村庄加入Treap,可以高效地查询特定村庄所在的联通块范围及村庄数量,并在修复村庄时将其从Treap中移除。
2162

被折叠的 条评论
为什么被折叠?



