2028E - Alice's Adventures in the Rabbit Hole
可以先从一条链的情况开始观察,然后发现每次都会选深度最小的子节点(minf(v)),可以看作一个短链剖分,不过我不是这么写的
g(v)表示的是f(v)是f(u)的几分之几
我推的式子是这两个,但是我没法证明g(v)不会等于2使得分母为0
但是我觉得因为g(x)一定是合法的所以显然2-g(v)不会为0
\(f(x)=\frac{1}{2}(f(u)+min(f(v))\)
\(g(x)=\frac{1}{2-g(v)}\)
呃上面是我的做法,下面稍微说一下题解做法
短链剖分以后每条链都是一个等差数列,由式子\(f(x)=\frac{1}{2}(f(u)+f(v))\)可知
所以知道链根部的值就可以算链里面每个节点的值,准确来说是用根的f(fa)来算
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define lowbit(x) (x & (-x))
#define pii pair<int, int>
#define mkp make_pair
const int N = 2e5 + 10, mod = 998244353;
int g[N], f[N], n, dep[N];
vector<int> E[N];
int qpow(int x, int y)
{
int res = 1;
while (y > 0)
{
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
int inv(int x)
{
return qpow(x, mod - 2);
}
int sub(int a, int b)
{
return (a - b < 0) ? (a - b + mod) : (a - b);
}
int add(int a, int b)
{
return (a + b > mod) ? (a + b - mod) : (a + b);
}
void dfs(int x, int u)
{
int mn = 0x3f3f3f3f, flag = -1;
for (int i : E[x])
{
if (i == u)
continue;
dfs(i, x);
if (dep[i] < mn)
flag = i, mn = dep[i];
}
if (x == 1)
{
f[x] = 1;
return;
}
if (flag == -1)
{
dep[x] = 1;
f[x] = 0;
g[x] = 0;
// cout<<x<<endl;
return;
}
dep[x] = mn + 1;
// cout<<g[flag]<<endl;
g[x] = inv(sub(2, g[flag]));
// cout<<x<<' '<<flag<<' '<<g[flag]<<' '<<g[x]<<endl;
}
void dfs2(int x, int fa)
{
for (int i : E[x])
{
if (i == fa)
continue;
f[i] = f[x] * g[i] % mod;
// cout<<"MK"<<i<<' '<<f[x]<<' '<<g[i]<<endl;
dfs2(i, x);
}
return;
}
void solve()
{
cin >> n;
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
E[u].push_back(v);
E[v].push_back(u);
}
dfs(1, 0);
dfs2(1, 0);
for (int i = 1; i <= n; i++)
cout << f[i] << ' ', f[i] = g[i] = dep[i] = 0, E[i].clear();
cout << endl;
}
signed main()
{
ios::sync_with_stdio(false);
int T;
cin >> T;
while (T--)
solve();
}