题意:
帝国军团要去打击我们的反抗军团,但是他们在打击的时候特别有素质,因为总是要按照顺序去打击(笑),但是反抗军团的高智商人群都死光了需要我们去统计在每次打击后现存的联通块数量,并输出
分析:
这道题,如果按死脑筋去做,想着都头皮发麻,毕竟要先创造并查集,然后又要去删除并查集,之前小编想按着这种方法去做,但貌似要用到维护森林之类的高端,彻底疯掉了。但这一题,我们可以使用逆向思维:拆掉(摧毁)→修复。这样我们就可以先构建一个图,然后将每次帝国军团要摧毁的点进行标记,最后用并查集去判断联通。(更详细看代码)
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int tot,f[400001],head[400001],b[400001],broken[400001],ans[400001];
struct w{
int next,node,from;
}h[400001];
void jt(int x,int y)
{
h[++tot].from=x;
h[tot].next=head[x];
head[x]=tot;
h[tot].node=y;
return;
}
int find(int i)
{
return f[i]==i? i:f[i]=find(f[i]);
}
void hb(int x,int y)
{
int a,b;
a=find(f[x]);b=find(f[y]);
f[a]=b;
}
int main()
{
int n,m;
n=read();m=read();
int a,c;
for(int i=0;i<=n;i++)
f[i]=i,head[i]=-1;
for(int i=1;i<=m;i++)
{
a=read();c=read();
jt(a,c);
jt(c,a);
}
int k;
k=read();
for(int i=1;i<=k;i++)
{
b[i]=read();
broken[b[i]]=1;
}
int d=n-k;
for(int i=1;i<=m*2;i++)
if(!broken[h[i].from]&&!broken[h[i].node]&&find(h[i].from)!=find(h[i].node))
{
hb(h[i].from,h[i].node);
d--;
}
ans[k+1]=d;
for(int i=k;i>0;i--)
{
d++;
broken[b[i]]=0;
for(int j=head[b[i]];j!=-1;j=h[j].next)
{
if(!broken[h[j].node]&&find(b[i])!=find(h[j].node))
{
d--;
hb(h[j].node,b[i]);
}
}
ans[i]=d;
}
for(int i=1;i<=k+1;i++) printf("%d\n",ans[i]);
return 0;
}