標籤:oid 目的 targe nod size for har 答案 描述
傳送門
這道題看題目描述……聯通具有傳遞性?很容易想到是並查集。
不過按照題目的描述似乎很麻煩……這樣每次摧毀會令人很難受。不過這並不是問題,我們把它倒過來,從最終被摧毀的狀態開始,直接往回加邊,每次用並查集維護即可。
還有就是如何計算聯通塊數?一開始我智障般的想了好久……後來被mrclr一語道破:從一開始剩餘的星球數開始計算,每次合并兩個就將總數--,每次新加入一個星球先++,之後仿照上面的方式繼續計算,把答案存起來即可。
上代碼。
#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define rep(i,a,n) for(int i = a;i <= n;i++)#define per(i,n,a) for(int i = n;i >= a;i--)#define enter putchar(‘\n‘)using namespace std;const int M = 200005;typedef long long ll;int read(){ int ans = 0,op = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) op = -1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) { ans *= 10; ans += ch - ‘0‘; ch = getchar(); } return ans * op;}struct node{ int next,to,from;}e[M<<1];int n,m,x,y,des[M<<1],fa[M<<1],head[M<<1],ecnt,k,sum,ans[M<<1],p;bool vis[M<<1];void add(int x,int y){ e[++ecnt].to = y; e[ecnt].from = x; e[ecnt].next = head[x]; head[x] = ecnt;}int getfa(int x){ if(fa[x] == x) return fa[x]; else return fa[x] = getfa(fa[x]);}int main(){ n = read(),m = read(); rep(i,0,n-1) fa[i] = i; rep(i,1,m) x = read(),y = read(),add(x,y),add(y,x); k = read(),sum = n-k,p = n; rep(i,1,k) des[i] = read(),vis[des[i]] = 1; rep(i,0,n-1) { if(vis[i]) continue; int r1 = getfa(i); for(int j = head[i];j;j = e[j].next) { if(vis[e[j].to]) continue; int r2 = getfa(e[j].to); if(r1 != r2) fa[r2] = r1,sum--; } } ans[k] = sum; per(i,k,1) { vis[des[i]] = 0,sum++; int r1 = getfa(des[i]); for(int j = head[des[i]];j;j = e[j].next) { if(vis[e[j].to]) continue; int r2 = getfa(e[j].to); if(r1 != r2) fa[r2] = r1,sum--; } ans[i-1] = sum; } rep(i,0,k) printf("%d\n",ans[i]); return 0;}
JSOI2008 星球大戰