2 条题解
-
2
写的不好,欢迎提出改进👀️
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAXI=4e5+4; int f[MAXI],head[MAXI],h[MAXI],ans[MAXI],En=0; bool e[MAXI]; int find(int x) { if(x!=f[x]) f[x]=find(f[x]); return f[x]; } struct edge { int from; int to; int next; }a[MAXI]; void insert(int u,int v) { a[En].from=u; a[En].next=head[u]; a[En].to=v; head[u]=En; En++; } int main() { int n,m,k,x,y,tot,i,u; cin>>n>>m; for(i=0;i<n;++i) { f[i]=i; head[i]=-1; } for(i=0;i<m;++i) { cin>>x>>y; insert(x,y);insert(y,x); } cin>>k; tot=n-k; for(i=1;i<=k;i++) { cin>>x; e[x]=true; h[i]=x; } for(i=0;i<2*m;i++) { if(e[a[i].from]==false&&e[a[i].to]==false) { if(find(a[i].from)!=find(a[i].to)) { tot--; f[find(a[i].from)]=f[find(a[i].to)]; } } } ans[k+1]=tot; for(int t=k;t>=1;t--) { u=h[t]; tot++; e[u]=false; for(i=head[u];i!=-1;i=a[i].next) { if(e[a[i].to]==false&&f[find(u)]!=f[find(a[i].to)]) { tot--; //合并 f[find(a[i].to)]=f[find(u)]; } } ans[t]=tot; } for(i=1;i<=k+1;++i) cout<<ans[i]<<endl; return 0; }
-
1
本题的目的是各个时间求联通块的个数,从最后时刻往前做,并查集的初始状态即被破坏后的图。
主要思想是,并查集中处于一个联通块的祖先结点相等,当任意祖先不同两个联通块联通时,联通块会减少一个(同时当破坏的被恢复时会增加一个),通过这种操作可以知道目前有多少个联通块。
而本题只需要知道是否在一个并查集中就可知道是否增删联通块了,因此核心算法不是很难。
具体操作说明附在代码里
#include<bits/stdc++.h> using namespace std; const int N=4000005,M=2000005; struct node{ int y,next; }b[2*M]; struct node1{ int x,y; }a[M]; int n,m,k,s,t,mm,head[N],fa[N],tot,f[N],c[N],ans,g[N]; //f 0 未摧毁 1 摧毁 void add(int s,int t){ b[++tot].y=t; b[tot].next=head[s]; head[s]=tot; } int getfa(int x){ if (fa[x]==x) return x; fa[x]=getfa(fa[x]); return fa[x]; } void link(int s,int t){ int ss=getfa(s); int tt=getfa(t); if (ss!=tt){ ans--; fa[ss]=tt; } } int main() { cin>>n>>mm; for (int i=1;i<=n;++i) fa[i]=i; for (int i=1;i<=mm;++i){ cin>>s>>t; ++s;++t; a[i].x=s;a[i].y=t;//保存所有边 add(s,t);add(t,s); } cin>>m; for (int i=1;i<=m;++i){ cin>>c[i]; c[i]++; f[c[i]]=1; } ans=n-m;//初始答案为总星球数-被破坏的星球数 for (int i=1;i<=mm;++i){ if (f[a[i].x]==0&&f[a[i].y]==0) link(a[i].x,a[i].y); //遍历所有边,如果两条边都存在,则合并并查集 } g[m+1]=ans;//记录答案 for (int i=m;i>=1;--i){ f[c[i]]=0; ans++; for (int k=head[c[i]];k;k=b[k].next){ int y=b[k].y; if (f[y]==0) link(c[i],y); //对应边存在,则合并并查集 } g[i]=ans; } for (int i=1;i<=m+1;++i) cout<<g[i]<<endl; }
- 1
信息
- ID
- 67
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 4
- 标签
- 递交数
- 136
- 已通过
- 62
- 上传者