ABC235E MST+1 题解
题目大意
给你一个图 \(G\) 含有 \(n\) 个顶点和 \(m\) 条边,给出 \(Q\) 次询问,询问所多输入的边加上原图 \(G\) 的最小生成树是否是存在 \(e_i\),存在输出 Yes
不存在输出
No
。
思路
首先我们可以想到用最简单的方法,在每次询问时都做一次 Kruskal
算法,如果这个边被取到了,那么输出
Yes
,反之亦然。时间复杂度为 \(\mathcal{O}(Q \times n \log
n)\),太慢。
因为每个询问是相互独立的,而且询问的边 \(e_i\) 对于 并查集
的不会产生影响,所以可以想到只用一次 Kruskal
算法,把所有的边都涵盖上。
在遍历时每条边的处理方法:
如果是询问的 \(e_i\) 的边
如果是询问的 \(e_i\) 的边
如果是 \(G\) 的边
时间复杂度 \(\mathcal{O}((n+Q) \log (n +
Q))\)。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| #include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<vector>
using namespace std;
const int maxn = 200005;
struct Edge{int u,v,w,Is,num;}; int fa[maxn]; Edge e[maxn*2]; bool ans[maxn]; int n,m,q; vector<Edge> qe;
bool operator ==(const Edge &a,const Edge &b){return (a.u == b.u && a.v == b.v && a.w == b.w);}
int found(int x){ return fa[x] == x ? x : fa[x] = found(fa[x]); }
bool cmp(Edge x,Edge y){ return x.w < y.w; }
inline void Init_Onion(){ for(int x=1;x<=n;x++) fa[x] = x; memset(ans,0,sizeof(ans)); }
int main() { scanf("%d %d %d",&n,&m,&q); for(int i=1;i<=m;i++){ scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].w); e[i].Is = 0; }
for(int i=1;i<=q;i++){ scanf("%d %d %d",&e[m+i].u,&e[m+i].v,&e[m+i].w); e[m+i].Is = 1;e[m+i].num = i; }
sort(e+1,e+m+q+1,cmp); Init_Onion();
int k = 0; for(int i=1;i<=m+q;i++){ if(e[i].Is == 1){ if(found(e[i].v) != found(e[i].u)) ans[e[i].num] = 1; continue; }
int u = e[i].u,v = e[i].v; int f = found(u),t = found(v); fa[t] = f; }
for(int i=1;i<=q;i++){ if(ans[i] == 1) printf("Yes\n"); else printf("No\n");#191B1C } return 0; }
|