[luogu1197] [JSOI2008]星球大战
Posted Neworld2002
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[luogu1197] [JSOI2008]星球大战相关的知识,希望对你有一定的参考价值。
看到联通块,好像跟并查集、强连通分量有关系吧,仔细一看跟哪些点属于哪些块没关系,只关心联通块数量,那么应该可以用并查集做。继续看,这是一道删边的题,好像很难维护删边,我们又知道并查集是可以维护加边的,那么我们就倒过来做好了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 400005
struct Node{
int u,v;
}E[MAXN];
struct edge{
int v,next;
}G[MAXN];
int fa[MAXN],vis[MAXN];
int ed[MAXN],ans[MAXN];
int head[MAXN];
int N,M,K,tot=0;
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline void merge(int u,int v){
fa[find(u)] = find(v);
}
inline void add(int u,int v){
G[++tot].v = v ;G[tot].next = head[u];head[u] = tot;
}
int main(){
scanf("%d%d",&N,&M);
for(register int i=0;i<N;++i){
fa[i] = i;
}
std::memset(head,0,sizeof(head));
std::memset(vis,0,sizeof(vis));
for(register int i=1;i<=M;++i){
scanf("%d%d",&E[i].u,&E[i].v);
add(E[i].u,E[i].v);
add(E[i].v,E[i].u);
}
scanf("%d",&K);
int count = N-K;
for(register int i=K;i>=1;--i){
scanf("%d",&ed[i]);
vis[ed[i]] = 1;
}
for(register int i=1;i<=M;++i){
int u = E[i].u;int v = E[i].v;
if(vis[u]||vis[v]||(find(u)==find(v)))continue;
merge(u,v);
count--;
}
ans[0] = count;
for(register int i=1;i<=K;++i){
vis[ed[i]] = 0;
count++;
for(register int j=head[ed[i]];j;j=G[j].next){
int v = G[j].v;
if(!vis[v]&&find(v)!=find(ed[i])){
merge(v,ed[i]);
count--;
}
}
ans[i] = count;
}
for(register int i=K;i>=0;--i){
printf("%d
",ans[i]);
}
return 0;
}
以上是关于[luogu1197] [JSOI2008]星球大战的主要内容,如果未能解决你的问题,请参考以下文章
Luogu P1197 [JSOI2008]星球大战 By cellur925