Develop a Tree 题解
zgy_123
2024-08-03 12:35:37
![](https://cdn.luogu.com.cn/upload/image_hosting/zxxf3qro.png)
~~感觉太板了~~。
## subtask 1
考虑二分图的性质:
> 二分图不存在长度为奇数的环。
由于加边后树变为基环树,有且只有一个环。易得对答案有贡献的点,距离只能为奇数,这样才可以保证产生的环长为偶数。
记 $d(X,Y)$ 为 $X$ 和 $Y$ 之间的距离,$R$ 为根节点,$L$ 当前两个节点的 LCA。
根据 LCA,两个点的距离为:
$$d(X,Y)=d(x,R)+d(y,R)-2d(L,R)$$
然而本题中仅需要求路径长度的奇偶性,所以有:
$$d(X,Y)\equiv(x,R)+d(y,R)(\operatorname{mod} 2)$$
得出结论:
> 两个点距离为奇数,当且仅当其到根节点距离和为奇数。
又根据小学数学,只有奇数加偶数为奇数,即:
> 两个点距离为奇数,当且仅当其中一个点到根节点距离为偶数,而另一个节点到根节点距离为奇数。
所以这个题实际上是求:在 $i$ 的子树中到 $i$ 距离为偶数(奇数)的点的数量,乘积即为 $f(i,1)$。
考虑 dfs 的同时维护一个 dp 数组,其中 $dp_{i,x}$ 表示 $i$ 的子树中到 $i$ 的距离模 $2$ 为 $x$ 的点的个数。
有转移式(令 $v$ 为 $u$ 的儿子):
$$dp_{u,0}=\sum dp_{v,1}+1$$
$$dp_{u,1}=\sum dp_{v,0}$$
输出 $f(i,1)=dp_{i,0}\times dp_{i,1}$ 即可。复杂度 $O(n)$。
## subtask 2
可以直接枚举每个点对,计算距离。但是问题在于 $k>1$。
不难发现添加 $k$ 条边等价于在可添加的边里选 $k$ 条。所以 $f(i,k)=C_{f(i,1)}^{k}$。
由于模数是质数,可以直接 $O(k)$ 求组合数。
## subtask 3,4
将 subtask1 和 subtask2 的做法结合起来即可,时间复杂度 $O(\sum k\log_2p_i)=O(nk\log p)$,TLE。
所以考虑优化掉 $\log$,显然可以开个桶预处理逆元,于是就做完了。
std by caosheng_zzz:
```cpp
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <map>
#include <set>
typedef int intt ;
#define prt printf
#define ll long long
#define int __int128
#define spc prt(" ")
#define ent prt("\n")
#define pr_ prt("---")
#define prx prt("***")
using namespace std;
int read(){
int f = 1 , k = 0;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-') f = -1;
c = getchar() ;
}
while(c >= '0' && c <= '9'){
k = (k << 3) + (k << 1) + (c ^ 48);
c = getchar() ;
}
return (f == 1 ? k : -k);
}
void output(int now){
if(now < 0){
putchar('-');
output(- now);
}
else{
if(now > 9) output(now / 10);
putchar((now % 10) ^ 48);
}
}
const intt maxn = 5e5 + 1;
const ll Mod[] = {0 , 999998003 , 999998017 , 999998023 , 999998059 , 999998081 , 999998107 , 999998119 , 999998137 , 999998141 , 999998143 , 999998147 , 999998173 , 999998183 , 999998203 , 999998243 , 999998261 , 999998269 , 999998309 , 999998339 , 999998369 , 999998423 , 999998459 , 999998501 , 999998507 , 999998509 , 999998533 , 999998537 , 999998563 , 999998609 , 999998617 , 999998621 , 999998627 , 999998639 , 999998641 , 999998653 , 999998663 , 999998683 , 999998687 , 999998689 , 999998693 , 999998777 , 999998789 , 999998801 , 999998843 , 999998863 , 999998869 , 999998903 , 999998917 , 999998921 , 999998929 , 999998957 , 999998959 , 999998971 , 999998981 , 999999001 , 999999017 , 999999029 , 999999043 , 999999059 , 999999067 , 999999103 , 999999107 , 999999113 , 999999131 , 999999137 , 999999151 , 999999163 , 999999181 , 999999191 , 999999193 , 999999197 , 999999223 , 999999229 , 999999323 , 999999337 , 999999353 , 999999391 , 999999433 , 999999487 , 999999491 , 999999503 , 999999527 , 999999541 , 999999587 , 999999599 , 999999607 , 999999613 , 999999667 , 999999677 , 999999733 , 999999739 , 999999751 , 999999757 , 999999761 , 999999797 , 999999883 , 999999893 , 999999929 , 999999937};
intt cnt = 0 , h[maxn] ;
intt f[maxn][2];
struct Edge{
intt next , to;
}edge[maxn << 1];
map<ll , intt> G ;
ll g[100][21] , mul[100][21];
intt cour = 0 ;
void add(intt u , intt v){
edge[++ cnt] = {h[u] , v};
h[u] = cnt;
}
void dfs(intt u , intt fa , intt deep){
f[u][deep % 2] ++ ;
// output(u) , spc , output(fa) , spc , output(deep) , ent;
for(intt i=h[u] ; i ; i=edge[i].next){
intt v = edge[i].to ;
// output(u) , spc , output(v) , ent;
if(v == fa) continue ;
dfs(v , u , deep + 1) ;
f[u][0] += f[v][0] , f[u][1] += f[v][1];
}
return ;
}
int power(int base , ll s , ll p){
int res = 1;
while(s){
if(s & 1) res = res * base % p;
base = base * base % p;
s >>= 1;
}
return res;
}
ll C(intt a , int b , ll p){
int res = 1 ; intt num = G[p];
if(b == 0 || a == 0) return 0 ;
if(a > b) return 0 ;
if(a == 1) return b % p ;
if(a >= p) return 0 ;
for(int i=1 ; i<=a ; i++){
res = res * (b - i + 1) % p * mul[num][i] % p;
}
return res;
}
signed main(){
// ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n = read() , k = read() ;
for(int i=1 ; i<=100 ; i++) { G[Mod[i]] = i ; for(int j=1 ; j<=k ; j++) mul[i][j] = power(j , Mod[i] - 2 , Mod[i]) ;}
for(int i=1 ; i<n ; i++){
intt u , v ;
cin >> u >> v ;
add(u , v) , add(v, u);
}
dfs(1 , 0 , 1);
for(int i=1 ; i<=n ; i++) { output(C(k , (__int128)f[i][0] * f[i][1] , read())) , i == n ? ent : spc ;}
return 0;
}
```
- 这个题所有人都认为不应该放 T4,但是最后还是放了。
- 题太水请见谅。
- 感谢阅读!