P1197 [JSOI2008]星球大战
这道题跟猴子那道题差不多,挺简单的一个倒序并查集,变拆为建,把被毁的做标记,每个点可连的边也记录下来,先把能连的都连起来,然后从最后一个被毁的星球开始连可以连的边(指此时对方星球未被摧毁)作为下一个被毁星球重建的基础。细节比较多。
#include <iostream> #include <cstdio> #include <vector> #define MA 400002 using namespace std; int n,m,a[MA],b[MA],f[MA],t,star[MA],broken[MA],iis[MA],tot; vector <int> son[200002]; int find(int x){ if(f[x]!=x) f[x]=find(f[x]); return f[x]; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&a[i],&b[i]); son[a[i]].push_back(b[i]); son[b[i]].push_back(a[i]); } for(int i=0;i<n;i++) f[i]=i; scanf("%d",&t); for(int i=1;i<=t;i++){ scanf("%d",&star[i]); broken[star[i]]=-1; } for(int i=1;i<=m;i++){ int x=a[i],y=b[i]; if(broken[x]==-1||broken[y]==-1) continue; else{ int fx=find(x); int fy=find(y); if(fx!=fy) f[fx]=fy; } } for(int i=t;i>=1;i--){ //printf("%d ",broken[2]); tot=0; for(int j=0;j<n;j++) if(f[j]==j&&broken[j]!=-1) tot++; //cout<<endl; iis[i]=tot; for(int j=0;j<son[star[i]].size();j++){ int x=star[i],y=son[star[i]][j]; if(broken[y]==-1) continue; //printf("%d %d\n",x,y); int fx=find(x); int fy=find(y); if(fx!=fy) f[fx]=fy; } broken[star[i]]=0; } tot=0; for(int i=0;i<n;i++) if(f[i]==i) tot++; iis[0]=tot; for(int i=0;i<=t;i++) printf("%d\n",iis[i]); return 0; }
这是我最初的代码,想着每次干完之后都求一次目前有多少f【i】=i的,结果tle了一大堆。
#include <iostream> #include <cstdio> #include <vector> #define MA 400002 using namespace std; int n,m,a[MA],b[MA],f[MA],t,star[MA],broken[MA],iis[MA],tot; vector <int> son[400002]; int find(int x){ if(f[x]!=x) f[x]=find(f[x]); return f[x]; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d",&a[i],&b[i]); son[a[i]].push_back(b[i]); son[b[i]].push_back(a[i]); } for(int i=0;i<n;i++) f[i]=i; scanf("%d",&t); for(int i=1;i<=t;i++){ scanf("%d",&star[i]); broken[star[i]]=-1; } tot=n-t; for(int i=1;i<=m;i++){ int x=a[i],y=b[i]; if(broken[x]==-1||broken[y]==-1) continue; else{ int fx=find(x); int fy=find(y); if(fx!=fy){ f[fx]=fy; tot--; } } } iis[t+1]=tot; for(int i=t;i>=1;i--){ //printf("%d ",broken[2]); tot++; //cout<<endl; broken[star[i]]=0; for(int j=0;j<son[star[i]].size();j++){ int x=star[i],y=son[star[i]][j]; if(broken[y]==-1) continue; //printf("%d %d\n",x,y); int fx=find(x); int fy=find(y); if(fx!=fy){ f[fy]=fx; tot--; } } iis[i]=tot; } for(int i=1;i<=t+1;i++) printf("%d\n",iis[i]); return 0; }
后来看了看题解,有位大神非常厉害,初始tot计数为n-t(即未被摧毁的所有城市)合并时可以合并就-1,每一个被摧毁的星球重建tot就++,可以和对方星球合并就再-1,见识了见识了。