ABC235E-MST+1题解

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\) 的所连的两个顶点 \(u,v\) 没有连通,则标记为 Yes

    • 如果连通,则标记为 No

  • 如果是询问的 \(e_i\) 的边

    • 如果 \(e_i\) 的所连的两个顶点 \(u,v\) 没有连通,则标记为 Yes

    • 如果连通,则标记为 No

  • 如果是 \(G\) 的边

    • 将两个顶点在并查集内合并

时间复杂度 \(\mathcal{O}((n+Q) \log (n + Q))\)

代码如下:

#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");
    }    
    return 0;
}
posted @ 2022-01-29 19:02  在那遥远的悠穹下  阅读(40)  评论(0编辑  收藏  举报