HDU - 4496 City (逆向并查集)

题意:有N个点M条边的无向图,每次删除一条边直到删完为止,求每一次删边操作之后,连通块的个数。

M<=1e5,N<=1e4。如果每次删边之后暴力求连通块肯定超时。换个思路,对一个N阶零图,我们用并查集表示每一个点为独立的连通块,然后每次加边后检查边连接的两点是否已在一个连通块中,以此求出每次加边后的连通块个数。

那么可以把删边的过程倒过来离线处理。

#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn = 1e4+5;
const int INF= 0x3f3f3f3f;
struct OP{int u,v; }p[maxn*10];
int fa[maxn];
int ans[maxn*10];
void init(int N){ for(int i=0;i<=N;++i) fa[i]=i;}
inline int Find(int x){return fa[x]==x? x:fa[x]= Find(fa[x]);}
void Union(int a,int b){
    a = Find(a), b= Find(b);
    if(a!=b) fa[a]= b;
}

int main()
{
    #ifndef ONLINE_JUDGE
         freopen("in.txt","r",stdin);
         freopen("out.txt","w",stdout);
    #endif
    int T,N,M,Q,u,v,tmp,K,cas=1;
    while(scanf("%d%d",&N,&M)==2){
        init(N);
        for(int i=1;i<=M;++i) scanf("%d%d",&p[i].u,&p[i].v);
        int res=N;
        for(int i=M;i>=1;--i){
            int u = p[i].u, v= p[i].v;
            u = Find(u),v = Find(v);
            ans[i] = res;
            if(u!=v){
                Union(u,v);
                res--;
            }
        }
        for(int i=1;i<=M;++i) printf("%d\n",ans[i]);
    }
    return 0;
}

 

posted @ 2018-08-03 15:14  xiuwenL  阅读(158)  评论(0编辑  收藏  举报