题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4496
写在前边:期末考试忙的焦头烂额,平时没学习的后果啊,整理道题先。
题目大意:就是告诉你有n个城市,m条边,这个人每经过一条边会摧毁它,问你每摧毁一条边他剩下的连通块是多少(一开始所有的点都是连在一起的,且最后所有的点都是不连通的)
题目思路:正向的化会非常的麻烦,因为你无法确定某一个状态下摧毁的边是不是以前就摧毁过的。那么我们就可以逆向思考这个问题;你的最后一个状态肯定是N因为所有的边都被摧毁了,也就是说你摧毁了所有,然后倒着重建,重建过程中每当碰到不是一个集合的点,它的联通分量就会减一。
总结一下:1)结构体储存点与边
2)建立一个答案数组
3)ans[i]=sum,然后倒着维护sum值(每当碰到不在一个集合的情况下,sum--)
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int pre[maxn];
struct node{
int u;
int v;
}p[maxn];
int ans[maxn];
void build()
{
for(int i=0;i<maxn;i++) pre[i]=i;
}
int Find(int x)
{
int p,tmp;
p=x;
while(x!=pre[x]) x=pre[x];
while(p!=x){
tmp=pre[p];
pre[p]=x;
p=tmp;
}
return x;
}
bool join(int x,int y)
{
int p=Find(x);
int q=Find(y);
if(p!=q){
pre[p]=q;
return false;//false为不是一个集合的情况
}
return true;
}
int main()
{
int n,m;while(~scanf("%d%d",&n,&m)){
build();
memset(ans,0,sizeof(ans));
for(int i=0;i<m;i++) scanf("%d%d",&p[i].u,&p[i].v);//初始化
int sum=n;
for(int i=m-1;i>=0;i--){
ans[i]=sum;
if(!join(p[i].u,p[i].v)) sum--;
}
for(int i=0;i<m;i++) printf("%d\n",ans[i]);
}
}