- 每个点反向寻找,从他的所有父节点将污水分一些出来
- 如果父节点没有计算过,再向上寻找其父节点···
- 如果父节点计算过,累加到自己
- 因为约等于每个点只会算一次, 核心代码复杂度是O(fa * n)
- 分数可以用pair<>代替
- 分数累加的时候,通分相加,long long 会溢出,所以要用高精度或者__int128
#include <bits/stdc++.h>
using namespace std;
typedef __int128 ll;
typedef pair<ll, ll> P;
ll n, m;
vector<ll> fa[100010];
ll chdN[100010];
bitset<100010> nok;
vector<ll> out;
P water[100010];
inline void add(P &A, const P &B)
{
A.first = (A.first * B.second + B.first * A.second);
A.second *= B.second;
ll g = __gcd(A.first, A.second);
A.first /= g;
A.second /= g;
}
inline P div(P A, ll B)
{
A.second *= B;
ll g = __gcd(A.first, A.second);
A.first /= g;
A.second /= g;
return A;
}
inline void dfs(ll now)
{
for (ll i = 0; i < fa[now].size(); i++)
{
if (nok[fa[now][i]])
{
dfs(fa[now][i]);
}
add(water[now], div(water[fa[now][i]], chdN[fa[now][i]]));
}
nok[now] = false;
}
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void write(__int128 x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9)
{
write(x / 10);
}
putchar(x % 10 + '0');
}
int main(int argc, char const *argv[])
{
n = read();
m = read();
for (ll i = 1; i <= n; i++)
{
chdN[i] = read();
if (chdN[i] == 0)
{
out.push_back(i);
continue;
}
for (ll j = 0; j < chdN[i]; j++)
{
ll v = 0;
v = read();
fa[v].push_back(i);
nok[v] = true;
}
}
for (ll i = 1; i <= m; i++)
{
nok[i] = false;
water[i] = make_pair(1LL, 1LL);
}
for (ll i = m + 1; i <= n; i++)
{
water[i].second = 1;
}
for (ll i = (m + 1); i <= n; i++)
{
if (nok[i])
{
dfs(i);
}
}
for (ll i = 0; i < out.size(); i++)
{
ll g = __gcd(water[out[i]].first, water[out[i]].second);
write(water[out[i]].first / g);
cout << " ";
write(water[out[i]].second / g);
cout << endl;
}
return 0;
}