【BZOJ1015】星球大战 并查集

我在那里想割顶和桥你却告诉我这是并查集,人与人之间的信任呢。。。

离线倒序操作,先将所有未被删除的点的子图用并查集连起来,倒序加入点即可

#include<cstdlib>
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define maxn 400005
using namespace std;
void _read(int &x)
{
	x=0; char ch=getchar();
	while(ch<'0' || ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return ;
}
void _readLL(long long &x)
{
	x=0; char ch=getchar();
	while(ch<'0' || ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return ;
}
struct edge
{
	int to,next;
}e[maxn*4];
bool v[maxn];
int cnt,n,m,k,head[maxn],edge_ct,f[maxn],a[maxn];
int Find(int x)
{
	if(f[x]==x)return x;
	else return f[x]=Find(f[x]);
}
void add(int x,int y)
{
	e[++edge_ct]=(edge){y,head[x]}; head[x]=edge_ct;
	return ;
}
void Init()
{
	_read(n); _read(m);
	int x,y;
	for(int i=1;i<=m;i++)
	{
		_read(x); _read(y);x++; y++;
		add(x,y); add(y,x);
	}
	_read(k);
	for(int i=1;i<=k;i++)
	{_read(a[i]);
	 a[i]++;v[a[i]]=1;}
	for(int i=1;i<=n;i++)f[i]=i;
	cnt=n-k;
	for(int i=1;i<=n;i++)if(!v[i])
	{
		for(int id=head[i];id;id=e[id].next)if(!v[e[id].to])
		{
			if(Find(i)!=Find(e[id].to))
			{
				cnt--; f[Find(i)]=Find(e[id].to);
			}
		}
	}
	return ;
}
int ans[maxn];
char s[35];int ct;
void out(int t)
{
	if(!t)
	{putchar('0'); putchar('\n');return ;}
	cnt=0;
	while(t){s[++ct]=t%10+'0'; t=t/10;}
	while(ct){putchar(s[ct]); ct--;}
	putchar('\n');
	return;
}
void work()
{
	for(int i=k;i>=0;i--)
	{
		ans[i]=cnt;
		if(i==0)break;
		for(int id=head[a[i]];id;id=e[id].next)if(!v[e[id].to])
		{
			if(Find(a[i])!=Find(e[id].to))
			{
				cnt--; f[Find(a[i])]=Find(e[id].to);
			}
		}
		v[a[i]]=false;cnt++;
	}
	for(int i=0;i<=k;i++)
	{
		out(ans[i]);
	}
	return;
}
int main()
{
	//freopen("in.txt","r",stdin);
	Init();
	work();
	return 0;
}


你可能感兴趣的:(并查集)