题解:CF1725I Imitating the Key Tree

· · 题解

2800?1800!

简单套路题。

首先我们发现这个限制有点太难处理,来考虑树上的链的最大值相关问题。

那么肯定是我们从小到大给边排个序再按照这个顺序连上,那我们每次考虑到一条边的时候,这条边两端所属的两个联通块之间的点的路径的最大值就是这条加进去的边的权值。(也可以说是 kruskal 重构树)

那么我们就需要通过构建一张图凑出这样的权值。

在树上加边的过程中同时也在我们的图上加边,显然我们想让两个联通块之间有环需要在两个联通块之间加上两条边。

一个观察是发现你可以随便选两个联通块中的两个点连边,并不会影响答案,这是因为我们不管怎么在联通块中选点连通性都不会发生改变,也就是说我们在加进去一条边后答案乘上 sz_u^2\times sz_v^2,然后接下来只需要考虑每次加进去两条边的权值。

显然我们加进去其中一条边的权值应该比当前所有加进图里的边都大(因为我们目前加进去的树边肯定是当前树边中最大),然后容易证明的是,我们按照这样的加边方式任意钦定合法权值,可以涵盖所有的树边上权值的选择方案。

接下来就是要对这个计数,形式化的,现在我们有一个排列 p

考虑递推,最后一个数肯定最大,然后倒数第二个数可以随便选一个,然后就有 $f_{2_i} = f_{2i-2}\times(2i-1)$。 于是就可以直接做了。 ```cpp #include<bits/stdc++.h> using namespace std; #define int long long const int mod = 998244353; int n; int ans = 1; int fa[100005],sz[100005]; int find(int x){ if(fa[x] == x)return x; return fa[x] = find(fa[x]); } void merge(int x,int y){ fa[x] = y;sz[y]+=sz[x]; } int pro = 1; signed main(){ cin >> n; for(int i = 2*n-3;i>=1;i-=2)pro = pro*i%mod; for(int i = 1;i<=n;i++)fa[i] = i,sz[i] =1; for(int i = 1;i<n;i++){ int a,b;cin>> a >> b; pro = pro*sz[find(a)]%mod*sz[find(a)]%mod*sz[find(b)]%mod*sz[find(b)]%mod; merge(find(a),find(b)); }cout << pro << endl; return 0; } /* 屋顶的天空是我们的 放学后夕阳也都会是我们的 不会再让步更多了 */ ```