BZOJ1015: [JSOI2008]星球大战starwar

来源:互联网 发布:中铁宝桥网络大学 编辑:程序博客网 时间:2024/06/06 00:52

要求支持图上的动态删点&&维护联通块个数

似乎这个要求4e5个点不太可做。。

正解是离线下来之后倒序用并查集加点

。。。长见识了

#include<bits/stdc++.h>  //#pragma comment(linker, "/STACK:1024000000,1024000000")   #include<stdio.h>  #include<algorithm>  #include<queue>  #include<string.h>  #include<iostream>  #include<math.h>  #include<set>  #include<map>  #include<vector>  #include<iomanip>  using namespace std;  #define ll long long  #define pb push_back  #define FOR(a) for(int i=1;i<=a;i++)  const int inf=0x3f3f3f3f;  const int maxn=4e5+9;       int fa[maxn];void init(int n){for(int i=0;i<n;i++)fa[i]=i;}int find(int x){return fa[x]==x?fa[x]:fa[x]=find(fa[x]);}void unite(int a,int b){a=find(a);b=find(b);fa[b]=a;} vector<int>Gf[maxn]; int n,m,k; int ou[maxn],ov[maxn]; vector<int>rem;vector<int>ans;bool vis[maxn]; int main(){    scanf("%d%d",&n,&m);    init(n);    for(int i=1;i<=m;i++){        scanf("%d%d",&ou[i],&ov[i]);        Gf[ou[i]].pb(ov[i]);        Gf[ov[i]].pb(ou[i]);    }         scanf("%d",&k);    for(int i=1,x;i<=k;i++){        scanf("%d",&x);        rem.pb(x);vis[x]=1;    }    reverse(rem.begin(),rem.end());     init(n);    int now=n-k;    for(int i=1;i<=m;i++){        if(!vis[ou[i]] && !vis[ov[i]]){            if(find(ou[i])!=find(ov[i])){                unite(ou[i],ov[i]);                now--;            }                   }    }     ans.pb(now);    //全部炸毁     for(int i=0;i<rem.size();i++){   //枚举炸毁点rem[i]        now++;        for(int j=0;j<Gf[rem[i]].size();j++){            if(find(rem[i])!=find(Gf[rem[i]][j]) && !vis[Gf[rem[i]][j]]){                now--;                unite(rem[i],Gf[rem[i]][j]);            }        }        ans.pb(now);        vis[rem[i]]=0;    }    for(int i=ans.size()-1;i>=0;i--){printf("%d\n",ans[i]);}}