CF891C Envy

Link

Solution

最小生成树有两个性质:

  • 在任意最小生成树上,任意权值的边数目是相同的;
  • 任意最小生成树,在加完了小于某权值的边之后,图的联通性是一样的。

所以先跑一遍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;
}

原文地址:https://www.cnblogs.com/fruitea/p/12208208.html