题目链接:Tachibana Kanade Loves Review


一道最小生成树好题。

考虑建图:
建立一个虚拟节点,对于已经完成的k个知识点,我们直接让虚拟节点与其相连。

然后对于m个关系,我们让其相连,最后求最下生成树即可。(可自己证明正确性)。


不过这道题卡常很恶心,我们可以玄学并查集的merge,因为数据很有可能卡我们并查集,卡成一条链,然后我们就随机合并,既可以保证近似的log的高度,然后加上路径压缩就可以跑得很快。

不过还有一种,因为数据很小,所以我们可以基数排序,消去一个log。

听说大神能贪心过!!!TQL!!!

注意:不要全开long long,会TLE。跑得不如int快,个别long long即可。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,k,s,cnt,f[N],tot; 
long long res,T;
struct node{
	int u,v,w;
}t[N*6];
int cmp(node a,node b){
	return a.w<b.w;
}
inline int read()
{
    int s = 0; char ch = getchar();
    while(!(ch >= '0' && ch <= '9' )) ch = getchar();
    while(ch >= '0' && ch <= '9'){s = s*10+ch-'0'; ch = getchar();}
    return s;
}
int find(int x){
	return x==f[x]?x:f[x]=find(f[x]);
}
signed main(){
	n=read(); m=read(); k=read(); scanf("%lld",&T); s=n+1;	f[s]=s;
	for(int i=1;i<=n;i++){
		f[i]=i;	int x;	x=read();	t[++tot]={s,i,x};
	}
	while(k--){
		int x;	x=read();	f[x]=s;
	}
	while(m--){
		int a,b,c;	a=read(); b=read(); c=read(); t[++tot]={a,b,c};
	}
	sort(t+1,t+1+tot,cmp);
	for(int i=1;i<=tot;i++){
		int fa=find(t[i].u); int fb=find(t[i].v);
		if(fa!=fb){
			res+=t[i].w;
			if(i&1)	f[fa]=fb;	else	f[fb]=fa;
			if(res>T)	break;
		}
	}
	puts(res>T?"No":"Yes");
	return 0;
}