[题解] [CF891C] Envy

Posted ztlztl

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解] [CF891C] Envy相关的知识,希望对你有一定的参考价值。

题面

题解

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

  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的主要内容,如果未能解决你的问题,请参考以下文章

CF891C Envy

「CF891C」Envy

[CF891C] Envy - Kruskal,并查集

CF 891C Envy 最小生成树+可撤销并查集

CodeForces - 891C: Envy(可撤销的并查集&最小生成树)

CF1512D Corrupted Array 题解