码迷,mamicode.com
首页 > 其他好文 > 详细

[题解] [CF891C] Envy

时间:2019-07-13 21:26:12      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:inline   ||   这一   连通性   getchar   for   tps   lse   flag   

题面

题解

对于同一个图中的最小生成树, 有如下性质

  1. 对于不同最小生成树中同一权值的边的数量是一定的, 可通过反证法证明, 在这里就不证了
  2. 对于任意正确加边方案, 加完小于某权值的边后连通性是一样的

所以根据以上性质, 可以判断某一权值能否在一棵最小生成树中同时出现, 具体方法如下

在Kruscal的过程中, 当把小于某一权值的所有边都处理完后, 对于这一权值的所有边, 记录下每条边两个端点所在的联通块

然后对于每组询问, 将边的权值排序后对于每一种权值单独考虑(每一种权值互不影响, 自己思考一下为什么), 看这些边形成的联通块中是否有环, 并查集判断即可, 至于撤销并查集, 暴力撤销即可

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#define itn int
#define reaD read
#define N 500005
using namespace std;

int n, m, fa[N]; 
struct edge { int from, to, cost, ancf, anct, id; } e[N]; 
struct Edge { int u, v, w; bool operator < (const Edge &p) const { return w < p.w; } }; 
vector <Edge> vec; 

inline int read()
{
    int x = 0, w = 1; char c = getchar();
    while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
    while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
    return x * w;
}

bool cmp1(edge x, edge y) { return x.cost < y.cost; }

bool cmp2(edge x, edge y) { return x.id < y.id; }

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

void merge(int u, int v) { u = find(u), v = find(v); fa[u] = v; }

int main()
{
    n = read(); m = read(); 
    for(int i = 1; i <= n; i++) fa[i] = i; 
    for(int i = 1; i <= m; i++) e[i].from = read(), e[i].to = read(), e[i].cost = read(), e[i].id = i; 
    sort(e + 1, e + m + 1, cmp1); 
    for(int i = 1; i <= m; )
    {
        int pos = i;
        do
        {
            e[pos].ancf = find(e[pos].from);
            e[pos].anct = find(e[pos].to); 
            pos++; 
        }
        while(pos <= m && e[pos].cost == e[pos - 1].cost);
        while(i < pos)
        {
            if(find(e[i].from) == find(e[i].to)) i++;
            else merge(e[i].from, e[i].to), i++; 
        }
    }
    for(int i = 1; i <= n; i++) fa[i] = i; 
    sort(e + 1, e + m + 1, cmp2); 
    int Q = read();
    while(Q--)
    {
        int k = read(); vec.clear(); 
        for(int i = 1; i <= k; i++)
        {
            int id = read(); 
            vec.push_back((Edge) { e[id].ancf, e[id].anct, e[id].cost }); 
        }
        sort(vec.begin(), vec.end());
        bool flag = 1; 
        for(int i = 0; i < vec.size(); )
        {
            if(!flag) break; 
            if(vec[i].u == vec[i].v) { flag = 0; break; };
            merge(vec[i].u, vec[i].v); 
            int pos = i + 1;
            while(pos < vec.size() && vec[pos].w == vec[i].w)
            {
                if(find(vec[pos].u) == find(vec[pos].v)) { flag = 0; break; }
                merge(vec[pos].u, vec[pos].v); pos++; 
            }
            while(i < pos) { fa[vec[i].u] = vec[i].u; fa[vec[i].v] = vec[i].v; i++; }
        }
        puts(flag ? "YES" : "NO"); 
    }
    return 0;
} 

[题解] [CF891C] Envy

标签:inline   ||   这一   连通性   getchar   for   tps   lse   flag   

原文地址:https://www.cnblogs.com/ztlztl/p/11182076.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!