并查集+时光倒流 || [JSOI2008]星球大战starwar || BZOJ 1015 || Luogu P1197

题面:P1197 [JSOI2008]星球大战

题解:

坑点有点多啊,加上我本来就有点头昏脑涨,一道水题写了一万年。。

并查集不支持拆开(但是可以撤销合并),只支持合并。所以把询问离线了,从最后状态到初状态开始一个个往当前图里加点。

CZL:对于只有删除点/边而不增加点/边,且允许离线的题,可以考虑时光倒流,先建出最终情况,再倒着把点/边加回去。

代码:

 1 #include
 2 using namespace std;
 3 inline int rd(){
 4     int x=0; char c=getchar();
 5     while(c<'0'||c>'9')c=getchar();
 6     while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
 7     return x;
 8 }
 9 const int maxn=4e5+5,maxm=2e5+5;
10 int N,M,fa[maxn],QUE[maxn],num_edge=0,edge_head[maxn];
11 int u,v,K,cnt=0,f1,f2,ans[maxn];
12 bool atkd[maxn];
13 struct Edge{ int to,nx; }edge[maxm<<1];
14 inline void Add_edge(int from,int to){
15     edge[++num_edge].nx=edge_head[from];
16     edge[num_edge].to=to;
17     edge_head[from]=num_edge;
18     return;
19 }
20 inline int getf(int n){
21     if(fa[n]==n) return n;
22     fa[n]=getf(fa[n]);
23     return fa[n];
24 }
25 int main(){
26     N=rd(); M=rd();
27     for(int i=0;ii;
28     for(int i=1;i<=M;i++){
29         u=rd(); v=rd();
30         Add_edge(u,v);
31         Add_edge(v,u);
32         f1=getf(u); f2=getf(v);
33         if(f1!=f2) fa[f1]=f2;
34     }
35     for(int i=0;i){
36         if(fa[i]==i) ans[0]++;
37         fa[i]=i;
38     }
39     K=rd();
40     for(int i=1;i<=K;i++){
41         QUE[i]=rd();
42         atkd[QUE[i]]=1;
43     }
44     for(int i=0;i)
45         if(atkd[i]==0){
46             for(int j=edge_head[i];j;j=edge[j].nx){
47                 int y=edge[j].to;
48                 if(atkd[y]) continue;
49                 f1=getf(i); f2=getf(y);
50                 if(f1!=f2) fa[f1]=f2;
51             }
52         }
53     for(int i=0;i)
54         if(atkd[i]==0&&fa[i]==i) cnt++;
55     for(int k=K;k>=1;k--){
56         ans[k]=cnt;
57         cnt++;
58         int x=QUE[k];
59         atkd[x]=0;
60         for(int i=edge_head[x];i;i=edge[i].nx){
61             int y=edge[i].to;
62             if(atkd[y]) continue;
63             f1=getf(x); f2=getf(y);
64             if(f1!=f2){
65                 cnt--;
66                 fa[f1]=f2;
67             }
68         }
69     }
70     for(int i=0;i<=K;i++) printf("%d\n",ans[i]);
71     return 0;
72 }
View Code

 


By:AlenaNuna

你可能感兴趣的:(并查集+时光倒流 || [JSOI2008]星球大战starwar || BZOJ 1015 || Luogu P1197)