BZOJ1015 星球大战starwar (并查集)

来源:互联网 发布:见过的高人 知乎 编辑:程序博客网 时间:2024/04/28 11:11

题目大意

给出一个n个点m条边的无向图,分k次删掉k个不同的点。每删掉一个点,这个点所连的边就会消失、无效。题目要求每次删点之后输出图中联通块个数。


题解

因为没法直接维护图中联通块个数并同时进行删点操作,所以可以将询问离线处理,把删点变成加点,每次加点都用并查集维护联通块个数就可以了。


代码

#include <cstdio>#include <iostream>using namespace std;const int maxn=int(5e5)+111;int n,m,k;int tot=0,head[maxn];bool occ[maxn],in[maxn];int q[maxn],ans[maxn];struct Edge {    int from,to,next;    Edge() {}    Edge(int x,int y,int nx):from(x),to(y),next(nx) {}}eage[maxn*2];void add(int x,int y) {    eage[tot]=Edge(x,y,head[x]), head[x]=tot++;    eage[tot]=Edge(y,x,head[y]), head[y]=tot++;    return;}int f[maxn];int _find(int k) {    if(k==f[k]) return k;    return f[k]=_find(f[k]);}int cur=0;void solve(int u) {    cur++;    in[u]=true;    for(int i=head[u];~i;i=eage[i].next) if(in[eage[i].to]) {        int v=eage[i].to, g1=_find(u), g2=_find(v);        if(g1!=g2) {cur--, f[g1]=g2;}    }    return;}int main() {#ifndef ONLINE_JUDGE    freopen("input.txt","r",stdin);    freopen("output.txt","w",stdout);#endif // ONLINE_JUDGE    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++) head[i]=-1;    for(int x,y,i=1;i<=m;i++) {        scanf("%d%d",&x,&y); x++,y++;        add(x,y);    }    scanf("%d",&k);    for(int i=1;i<=k;i++) {        scanf("%d",&q[i]), q[i]++;        occ[q[i]]=true;    }    for(int i=1;i<=n;i++) f[i]=i;    for(int u=1;u<=n;u++) if(!occ[u])        solve(u);    ans[k]=cur;    for(int i=k;i;i--)        solve(q[i]),        ans[i-1]=cur;    for(int i=0;i<=k;i++)        printf("%d\n",ans[i]);    return 0;}
1 0