BZOJ1015[JSOI2008]星球大战starwar题解报告
考虑正序去除点去掉其所有连边十分复杂,可以倒序离线处理,每次新建一个点,连接其连边,用并查集统计联通块的个数。
附代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=400000+5;
int ans[MAXN],fa[MAXN],rnk[MAXN],hd[MAXN],des[MAXN];
int ff[MAXN],tt[MAXN];
int to[MAXN<<1],nxt[MAXN<<1];
bool used[MAXN];
int cnt,n,m;
inline void build(int f,int t)
{
to[++cnt]=t;
nxt[cnt]=hd[f];
hd[f]=cnt;
}
int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool unite(int x,int y)
{
x=find(x),y=find(y);
if(x==y) return 0;
if(rnk[x]==rnk[y])
fa[x]=y,++rnk[y];
else if(rnk[x]>rnk[y])
fa[y]=x;
else
fa[x]=y;
return 1;
}
int main()
{
int x,y;
scanf("%d%d",&n,&m);
for(int i=0;i<=n;++i)
fa[i]=i;
for(int i=1;i<=m;++i)
{
scanf("%d%d",&ff[i],&tt[i]);
build(ff[i],tt[i]);
build(tt[i],ff[i]);
}
int k;
scanf("%d",&k);
for(int i=1;i<=k;++i)
scanf("%d",&des[i]),
used[des[i]]=1;
int ansn=n-k;
for(int i=1;i<=m;++i)
{
if(!used[ff[i]]&&!used[tt[i]])
{
if(unite(ff[i],tt[i]))
--ansn;
}
}
for(int j=k;j>=1;--j)
{
ans[j]=ansn;
++ansn;
int u=des[j];
used[u]=0;
for(int i=hd[u];i;i=nxt[i])
{
int v=to[i];
if(used[v]) continue;
if(unite(u,v))
--ansn;
}
}
printf("%d\n",ansn);
for(int i=1;i<=k;++i)
printf("%d\n",ans[i]);
return 0;
}