您的位置:首页 > Web前端 > JavaScript

【bzoj 1015[JSOI2008]星球大战starwar 反向并查集

2016-09-17 11:36 579 查看
首先,拿到这一道题,你是不是感觉好型有点并查集的意思。但是每一次破坏联通而并查集却只是支持每次合并,那好办,我们只需要先全部输入,然后反着来,哪一个被破坏就像记录现在联通数作为此时的答案然后再联通,此时联通数一定减一,反着来就可以解决了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#define PB(a) push_back(a)
#include<stack>
#define maxn 400020
using namespace std;
int n,m,k,fa[maxn],br[maxn],vis[maxn];
vector<int >G[maxn];
stack<int >ans;
int find(int x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int cnt;
void te(int u){
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(vis[v])continue;
int dx=find(u);
int dy=find(v);
if(dx!=dy)cnt--;
if(dx!=dy)fa[dx]=dy;

}
if(vis[u])cnt++;
vis[u]=0;
}

int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
x++,y++;
G[x].PB(y);
G[y].PB(x);
}
for(int i=1;i<=n;i++)fa[i]=i;
scanf("%d",&k);
for(int i=1;i<=k;i++){
int x;
scanf("%d",&x);
x++;
vis[x]=1;
br[i]=x;
}
cnt=n-k;
for(int i=1;i<=n;i++){
if(!vis[i])te(i);
}
ans.push(cnt);
for(int i=k;i>=1;i--){
te(br[i]);
ans.push(cnt);
}
while(!ans.empty()){
printf("%d\n",ans.top());
ans.pop();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: