【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;
}