您的位置:首页 > Web前端 > JavaScript

bzoj1015 [JSOI2008]星球大战(离线操作+并查集)

2017-09-04 21:02 363 查看
正着做不好做。。。我们考虑把所有的询问存下来,倒着做,每次恢复一颗星球,连通块数量一定是单调不升的。每次就相当于合并两个集合了。

#include<cstdio>
int const N=400005;
struct edge{
int to,next;
}data[N<<1];
int n,m,K,fa
,a
,ans
,h
,num=0,sum=0;
bool vis
;
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
int xx=find(x),yy=find(y);
if(xx!=yy) fa[xx]=yy,sum--;
}
int main(){
//  freopen("a.in","r",stdin);
n=read();m=read();
for(int i=0;i<n;++i) fa[i]=i,vis[i]=true;
while(m--){
int x=read(),y=read();
data[++num].to=y;data[num].next=h[x];h[x
4000
]=num;
data[++num].to=x;data[num].next=h[y];h[y]=num;
}
K=read();
for(int i=1;i<=K;++i)
a[i]=read(),vis[a[i]]=false;
sum=n-K;
for(int x=0;x<n;++x) if(vis[x])
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(vis[y]) merge(x,y);
}
for(int i=K;i>=1;--i){
ans[i]=sum;
int x=a[i];vis[x]=true;sum++;
for(int j=h[x];j;j=data[j].next){
int y=data[j].to;
if(vis[y]) merge(x,y);
}
}
ans[0]=sum;
for(int i=0;i<=K;++i) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: