• CF892E Envy[最小生成树]


    题意:有一张 $n$ 个点$ m $条边的连通图。有$Q$ 次询问。每次询问给出 $k[i]$ 条边,问这些边能否同时出现在一棵最小生成树上。$n,m,Q,sum kle 500000$。


    这题利用到了最小生成树的一个性质,可以结合我记的最小生成树笔记。在加入所有权值前$i-1$大的边后,目前的权值第$i$大的一些边不管怎么加,连通性都是一样的,也就是连通块内的点集都是一样的,只不过有一些剩下的边或者连接两个块内点的边不合法罢了。于是可以在kruskal的时候先处理出对于每条边,他连接的两个连通块是什么(以当时的角度记录块上并查集祖先)。然后处理询问的时候,排序后对于权值相同的边,用并查集判断他们连接的连通块是否有环,即合不合法即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define dbg(x) cerr << #x << " = " << x <<endl
     8 #define dbg2(x,y) cerr<< #x <<" = "<< x <<"  "<< #y <<" = "<< y <<endl
     9 using namespace std;
    10 typedef long long ll;
    11 typedef double db;
    12 typedef pair<int,int> pii;
    13 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
    14 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
    15 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
    16 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
    17 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
    18 template<typename T>inline T read(T&x){
    19     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
    20     while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
    21 }
    22 const int N=5e5+7;
    23 int n,m,q,k;
    24 struct thxorz{
    25     int u,v,w,id;
    26     inline bool operator <(const thxorz&A){return w<A.w;}
    27 }e[N];
    28 struct stothx{int fx,fy,w;}g[N];
    29 int anc[N];
    30 int find_anc(int x){return x==anc[x]?x:anc[x]=find_anc(anc[x]);}
    31 
    32 inline void Kruskal(){
    33     sort(e+1,e+m+1);
    34     for(register int i=1;i<=n;++i)anc[i]=i;
    35     for(register int i=1,st=1;i<=m;++i)if(e[i].w^e[i+1].w){
    36         for(register int j=st;j<=i;++j)
    37             g[e[j].id].fx=find_anc(e[j].u),g[e[j].id].fy=find_anc(e[j].v);//dbg(e[j].id),dbg2(g[e[j].id].fx,g[e[j].id].fy);
    38         for(register int j=st;j<=i;++j)
    39             anc[find_anc(g[e[j].id].fx)]=find_anc(g[e[j].id].fy);
    40         st=i+1;
    41     }
    42 }
    43 int a[N],vis[N],cnt;
    44 inline bool cmp(int a,int b){return g[a].w<g[b].w;}
    45 inline void Query(){
    46     read(k);for(register int i=1;i<=k;++i)read(a[i]);a[k+1]=0;
    47     sort(a+1,a+k+1,cmp);
    48     for(register int i=1,st=1;i<=k;++i)if(g[a[i]].w^g[a[i+1]].w){
    49         for(register int j=st;j<=i;++j){//dbg(a[j]);
    50             int fx=find_anc(g[a[j]].fx),fy=find_anc(g[a[j]].fy);//dbg2(fx,fy);
    51             if(fx^fy)anc[fx]=fy,vis[++cnt]=fx;
    52             else{while(cnt)anc[vis[cnt]]=vis[cnt],--cnt;puts("NO");return;}
    53         }
    54         st=i+1;
    55         while(cnt)anc[vis[cnt]]=vis[cnt],--cnt;
    56     }
    57     puts("YES");
    58 }
    59 
    60 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
    61     read(n),read(m);
    62     for(register int i=1;i<=m;++i)read(e[i].u),read(e[i].v),g[i].w=read(e[i].w),e[i].id=i;
    63     Kruskal();
    64     for(register int i=1;i<=n;++i)anc[i]=i;
    65     read(q);while(q--)Query();
    66     return 0;
    67 }
    View Code

    总结:要理解kruskal本质和其性质,从而进行改造,注意连通块性质。

  • 相关阅读:
    算法——(转)动态规划入门
    iOS学习——(转)多线程
    iOS崩溃日志ips文件解析
    iOS学习——核心动画
    iOS学习——核心动画之Layer基础
    iOS学习——Quartz2D学习之UIKit绘制
    iOS学习——Quartz2D学习之DrawRect
    iOS模拟器使用
    (转)浅谈Session与Cookie的区别与联系
    Android Studio 受不了了
  • 原文地址:https://www.cnblogs.com/saigyouji-yuyuko/p/11654729.html
Copyright © 2020-2023  润新知