CF1857G Counting Graphs 题解
题目描述#
给定一棵最小生成树,求有多少张图的最小生成树是给定的树,并且这张图的所有边边权不超过 \(S\)。
思路#
考虑在最小生成树中加边。
我们回顾一下 Kruskal 的过程:
- 找到没被用过的,最小的边
- 判断这条边的两端是否在一个联通块中
- 加入这条边,将两端的联通块连在一起
根据第三条,我们可以得出一个结论:只要在加边时,保证加入的边是给定的边,这张图的最小生成树就一定是给定的树。
因此,在这两个联通块之间加任意一条大于给定边的边,最小生成树肯定不变。
设联通块 \(1\) 有 \(a\) 个元素,联通块 \(2\) 有 \(b\) 个元素,给定边长度为 \(w\),那么两个联通块中的点对就有 \(a\times b -1\) 对(最小生成树里的那对不算),每对点对有不连边、连一条权值为 \(w+1\) 的边、连一条权值为 \(w+1\) 的边 . . . 连一条权值为 \(S\) 的边,一共 \(S-w+1\) 种连法,\(ans=ans\times (S-w+1)^{a+b-1}\)。
跑一遍最小生成树,维护每个联通块的 \(size\) ,再统计答案即可。
没注释的 Code#
#include <bits/stdc++.h>
#define int long long
using namespace std;
struct Edge{
int u,v,w;
}E[200005];
int T,N,S,X,Y,Z;
int ans;
int Power(int base,int power){
int res=1;
while(power){
if(power&1) res=(res*base)%998244353;
base=(base*base)%998244353;
power>>=1;
}return res;
}
int fa[200005],sz[200005];
int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);}
int Kruskal(){
ans=1;
for(int i=1;i<=N;i++) fa[i]=i,sz[i]=1;
for(int i=1;i<N;i++){
int u=E[i].u;
int v=E[i].v;
int w=E[i].w;
int a=Find(u);
int b=Find(v);
if(a!=b){
if((w+1)<=S) ans=ans*Power(S-w+1,sz[a]*sz[b]-1)%998244353;
sz[b]+=sz[a];
fa[a]=b;
}
}return ans;
}
signed main()
{
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&N,&S);
for(int i=1;i<N;i++){
scanf("%lld%lld%lld",&E[i].u,&E[i].v,&E[i].w);
}sort(E+1,E+N,[](Edge a,Edge b){return a.w<b.w;});
printf("%lld\n",Kruskal());
}
return 0;
}
作者:Sundar-2022
出处:https://www.cnblogs.com/Sundar-2022/p/18031330
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
Codeforces
, 题解
标签:
Codeforces
, 题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】