【2025.7.28】模拟赛T4

首先需要发现一个结论
最终答案的 MST 方案,与原图的任意的一种 MST 方案相比,最多只能有一条边的差别。
因为若有两条有差别的话,那么一条染白,一条染黑,一定合法且更优。
\(sum\) 表示原图的一个 MST 答案,讨论三种情况:
\(sum > X\):无解
\(sum = X\):枚举不在 MST 中的每条边,求出强制其在 MST 中的答案。
设有 \(prob\) 条边的答案 \(= X\)
原图 MST 方案中那些边加上 prob 条可选的边,总共 \(n - 1 + prob\) 条边染不同颜色(总染色方案数减去染成同为白或同为黑的 \(2\) 种方案),剩下的随便选。
答案为 \((2^{n-1+prob} - 2)\times 2^{m-(n-1)-prob}\)

\(sum<X\)

与上一种情况类似,设有 \(prob\) 条边满足答案 \(= X\),有 \(ban\) 条边满足答案 \(< X\)

先确定原图 MST 方案那些边的颜色 \(p\), 然后从 \(prob\) 条边中至少选一条与 \(p\) 颜 色不同,且剩下的边中有 \(ban\) 条边也要与 \(p\) 颜色相同(这样才能保证选出的边符合:选出的最小合法边集合 \(= X\))。

答案为 \(2\times (2^{m-(n-1)-prob} - 2^{m-(n-1)-ban-prob})\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5,M=2e5+5;
const int mod=1e9+7;
struct node{
	int u,v,w;
}e[M*2];
struct point{
	int to,cs;
};
int t,n,m,x,sum=0,ans=0,tot=0;
int fa[N];
int mx[N][20],f[N][20];
int dep[N];
bool vis[M];
int pw[M];
vector<point> G[N];
bool cmp(const node &a,const node &b){
	return a.w<b.w;
}
int find(int x){
	if(fa[x]!=x)  fa[x]=find(fa[x]);
	return fa[x];
}
void kruskal(){
	for(int i=1;i<=n;++i)  fa[i]=i;
	sort(e+1,e+m+1,cmp);
	int t=0;
	for(int i=1;i<=m;++i){
		int uf=find(e[i].u);
		int vf=find(e[i].v);
		if(uf!=vf){
			fa[uf]=vf;
			t++;
			sum+=e[i].w;
			vis[i]=1;
			G[e[i].u].push_back({e[i].v,e[i].w});
			G[e[i].v].push_back({e[i].u,e[i].w});
			if(t==n-1)  break;
		}
	}
}
void dfs(int u,int fa){
	f[u][0]=fa;
	for(int i=1;i<=18;++i){
		f[u][i]=f[f[u][i-1]][i-1];
		mx[u][i]=max(mx[u][i-1],mx[f[u][i-1]][i-1]);
	}
	for(int i=0;i<G[u].size();++i){
		int v1=G[u][i].to,w1=G[u][i].cs;
		if(v1==fa)  continue;
		mx[v1][0]=w1;
		dep[v1]=dep[u]+1;
		dfs(v1,u);
	}
}
int lca(int x,int y){
	int res=0;
	if(dep[x]<dep[y])  swap(x,y);
	for(int i=18;i>=0;--i)
	  if(dep[f[x][i]]>=dep[y]){
	  	res=max(res,mx[x][i]);
	  	x=f[x][i];
	  }
	if(x==y)  return res;
	for(int i=18;i>=0;--i)
	  if(f[x][i]!=f[y][i]){
	  	res=max(res,max(mx[x][i],mx[y][i]));
	  	x=f[x][i];y=f[y][i];
	  }
	return max(res,max(mx[x][0],mx[y][0]));
}
signed main(){
	freopen("zhuzhu.in","r",stdin);
	freopen("zhuzhu.out","w",stdout);
	cin>>t;
	pw[0]=1;
	for(int i=1;i<=2e5;++i)
	  pw[i]=pw[i-1]*2%mod;
	while(t--){
		scanf("%lld%lld%lld",&n,&m,&x);
		for(int i=1;i<=m;++i)  scanf("%lld%lld%lld",&e[i].u,&e[i].v,&e[i].w);
		sum=0;
		ans=0;
		tot=0;
		memset(vis,0,sizeof(vis));
		memset(dep,0,sizeof(dep));
		for(int i=1;i<=n;++i)  G[i].clear();
		kruskal();
		if(sum>x){
			printf("0\n");
			continue;
		}
		if(sum==x){
			dep[1]=1;
			dfs(1,0);
			for(int i=1;i<=m;++i){
				if(vis[i])  continue;
				int val=lca(e[i].u,e[i].v);
				if(e[i].w==val)  tot++;
			}
			ans=((pw[n-1+tot]-2)%mod)*pw[m-(n-1)-tot]%mod;
		}
		else{
			dep[1]=1;
			dfs(1,0);
			int cnt=0;
			for(int i=1;i<=m;++i){
				if(vis[i])  continue;
				int val=lca(e[i].u,e[i].v);
				if(sum-val+e[i].w<x)  tot++;
				else if(sum-val+e[i].w==x)  cnt++;
			}
			ans=2*(pw[m-(n-1)-tot]-pw[m-(n-1)-tot-cnt]+mod)%mod;
		}
		printf("%lld\n",ans);
	}
	fclose(stdin);fclose(stdout);
	return 0;
}
posted @ 2025-07-28 21:08  TimeSpacerui  阅读(8)  评论(0)    收藏  举报