Link

Solution

最小生成树有两个性质:

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
  • 在任意最小生成树上,任意权值的边数目是相同的;
  • 任意最小生成树,在加完了小于某权值的边之后,图的联通性是一样的。

所以先跑一遍Kruskal,对每条边处理出加入权值比他小的边之后两端点所在的联通块。

对于每组询问用,把边按边权排序之后,并查集check一下就可以了。

Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define REP(i,a,b) for(int i=(a),ed=(b);i<=ed;++i)
inline int read(){
    register int x=0,f=1;register char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
    while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
    return f?x:-x;
}

const int N=5e5+10;
int n,m,k,q[N];
struct edge{int x,y,w,id,a,b;inline bool operator<(const edge &a){return w<a.w;}}e[N];
inline bool cmp_id(const edge &a,const edge &b){return a.id<b.id;}
int f[N];
inline int find(int x){return f[x]=f[x]==x?f[x]:find(f[x]);}
inline bool cmp(const int &a,const int &b){return e[a].w<e[b].w;}

inline bool Judge(){
    REP(i,1,k){
        f[e[q[i]].a]=e[q[i]].a;f[e[q[i]].b]=e[q[i]].b;
        if(e[q[i]].a==e[q[i]].b)return 0;
    }
    sort(q+1,q+k+1,cmp);
    REP(i,1,k){
        int x=f[e[q[i]].a],y=f[e[q[i]].b];
        if(x==y)return 0;
        f[x]=y;
    }
    return 1;
}

int main(){
    n=read(),m=read();
    REP(t,1,m)e[t]=(edge){read(),read(),read(),t,0,0};
    sort(e+1,e+m+1);
    REP(i,1,n)f[i]=i;
    REP(i,1,m){
        if(e[i].w^e[i-1].w){
            int j=i;
            do{
                e[j].a=find(e[j].x),e[j].b=find(e[j].y);
                ++j;
            }while(e[j].w==e[j-1].w&&j<=m);
        }
        int x=find(e[i].x),y=find(e[i].y);
        if(x^y)f[x]=y;
    }
    sort(e+1,e+m+1,cmp_id);
    int Q=read();
    while(Q--){
        k=read();REP(i,1,k)q[i]=read();
        if(Judge())puts("YES");
        else puts("NO");
    }
    return 0;
}
扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄