标签:type name == read ace find sdi 个性 cpp
最小生成树有两个性质:
所以先跑一遍Kruskal,对每条边处理出加入权值比他小的边之后两端点所在的联通块。
对于每组询问用,把边按边权排序之后,并查集check一下就可以了。
#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;
}
标签:type name == read ace find sdi 个性 cpp
原文地址:https://www.cnblogs.com/fruitea/p/12208208.html