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; }
为了更好的明天