1. 程式人生 > >[Luogu 1197] JSOI2008 星球大戰

[Luogu 1197] JSOI2008 星球大戰

() TE 操作 private const eof sca n) false

[Luogu 1197] JSOI2008 星球大戰

<題目鏈接>


我算是真的淪為聯賽選手了。

並查集裸題。

比較麻煩的是刪點。

但是從後往前加點就好操作很多。

所以考慮離線,先存圖,然後沒被刪的點之間,有邊就合並。

每加一個點進來,把連著這個點且當前沒被刪的點並進來,更新連通塊個數並存入答案。

最終按順序輸出答案即可。

#include <cstdio>
#include <cstring>
const int MAXN=400010,MAXM=200010;
bool gone[MAXN];
int n,m,k,sum,q[MAXN],ans[MAXN];
struct
Edge { int to; Edge *next; Edge(int to,Edge* next):to(to),next(next){} ~Edge(void) { if(next!=nullptr) delete next; } }*head[MAXN]; class UFS { private: bool exist[MAXN]; int f[MAXN]; int Find(int x) { return
x==f[x] ? x : f[x]=Find(f[x]); } public: UFS(int n) { memset(exist,0,sizeof exist); for(int i=0;i<n;++i) { head[i]=nullptr; f[i]=i; } } ~UFS(void) { for(int
i=0;i<n;++i) delete head[i]; } void Merge(int x,int y) { f[Find(y)]=Find(x); } int Count(void) { int ans=0; for(int i=0,t;i<n;++i) if(!gone[i] && !exist[t=Find(i)]) { ++ans; exist[t]=1; } return ans; } bool Connected(int x,int y) { return Find(x)==Find(y); } }; void AddEdges(int u,int v) { head[u]=new Edge(v,head[u]); head[v]=new Edge(u,head[v]); } int main(int argc,char** argv) { scanf("%d %d",&n,&m); static UFS *S=new UFS(n); for(int i=1,x,y;i<=m;++i) { scanf("%d %d",&x,&y); AddEdges(x,y); } scanf("%d",&k); for(int i=1;i<=k;++i) { scanf("%d",&q[i]); gone[q[i]]=true; } for(int u=0;u<n;++u) if(!gone[u]) for(Edge *i=head[u];i!=nullptr;i=i->next) { int v=i->to; if(!gone[v]) S->Merge(u,v); } ans[k]=sum=S->Count(); for(int j=k,u;j>=1;--j) { ++sum; gone[u=q[j]]=false; for(Edge *i=head[u];i!=nullptr;i=i->next) { int v=i->to; if(gone[v]==false && !S->Connected(u,v)) { --sum; S->Merge(u,v); } } ans[j-1]=sum; } for(int i=0;i<=k;++i) printf("%d\n",ans[i]); delete S; return 0; }

謝謝閱讀。

[Luogu 1197] JSOI2008 星球大戰