【CCPC-Final 2019】G. Game on the Tree
G. Game on the Tree
题意:Alice 和 Bob 在一棵树上博弈,初始棋子位于根(1号节点),双方轮流操作,每次将棋子移动到另一个格子,并保证每次移动到距离严格大于上一次,不能操作者输。给定一棵树,问有多少包含1节点的联通块为后手胜。
Solution
考虑树的直径,考虑树的直径,如果一开始棋子位于直径中点,则无论先手如何移动,后手总可以将棋子移动到任意一个关于直径中点的对称点,而先手不能再做这个操作,所以后手胜。反之先手胜利。
所以需要统计包含根节点且根恰好是直径中点的联通块个数。
长链剖分。复杂度 \(O(n)\)。
\(f_{x, i}\) 表示以 \(x\) 为 LCA 且深度不超过 \(i\) 的联通块个数。
(我好像很不会写打 tag 的长链剖分,所以存一下)。
Code
#include "bits/stdc++.h"
using namespace std;
using ui=unsigned; using db=long double; using ll=long long; using ull=unsigned long long; using lll=__int128;
using pii=pair<int,int>; using pll=pair<ll,ll>;
template<class T1, class T2> istream &operator>>(istream &cin, pair<T1, T2> &a) { return cin>>a.first>>a.second; }
template <std::size_t Index=0, typename... Ts> typename std::enable_if<Index==sizeof...(Ts), void>::type tuple_read(std::istream &is, std::tuple<Ts...> &t) { }
template <std::size_t Index=0, typename... Ts> typename std::enable_if<Index < sizeof...(Ts), void>::type tuple_read(std::istream &is, std::tuple<Ts...> &t) { is>>std::get<Index>(t); tuple_read<Index+1>(is, t); }
template <typename... Ts>std::istream &operator>>(std::istream &is, std::tuple<Ts...> &t) { tuple_read(is, t); return is; }
template<class T1> istream &operator>>(istream &cin, vector<T1> &a) { for (auto &x:a) cin>>x; return cin; }
template<class T1> istream &operator>>(istream &cin, valarray<T1> &a) { for (auto &x:a) cin>>x; return cin; }
template<class T1, class T2> bool cmin(T1 &x, const T2 &y) { if (y<x) { x=y; return 1; } return 0; }
template<class T1, class T2> bool cmax(T1 &x, const T2 &y) { if (x<y) { x=y; return 1; } return 0; }
istream &operator>>(istream &cin, lll &x) { x=0; static string s; cin>>s; for (char c:s) x=x*10+(c-'0'); return cin; }
ostream &operator<<(ostream &cout, lll x) { static char s[60]; int tp=1; s[0]='0'+(x%10); while (x/=10) s[tp++]='0'+(x%10); while (tp--) cout<<s[tp]; return cout; }
#if !defined(ONLINE_JUDGE)
#include "my_header/IO.h"
#include "my_header/defs.h"
#else
#define dbg(...) ;
#define dbgx(...) ;
#define dbg1(x) ;
#define dbg2(x) ;
#define dbg3(x) ;
#define DEBUG(msg) ;
#define REGISTER_OUTPUT_NAME(Type, ...) ;
#define REGISTER_OUTPUT(Type, ...) ;
#endif
#define all(x) (x).begin(),(x).end()
#define print(...) cout<<format(__VA_ARGS__)
#define err(...) cerr<<format(__VA_ARGS__)
const int mod1 = 998244353, mod2 = 1e9+7;
// #define MOD1
#ifdef MOD1
const int p = mod1; int fpow(int x,ll y=mod1-2,int m=mod1){int r=1;for(;y;y>>=1,x=(ll)x*x%m)if(y&1)r=(ll)r*x%m;return r;}
# else
const int p = mod2; int fpow(int x,ll y=mod2-2,int m=mod2){int r=1;for(;y;y>>=1,x=(ll)x*x%m)if(y&1)r=(ll)r*x%m;return r;}
# endif
int main()
{
ios::sync_with_stdio(0); cin.tie(0);
cout<<fixed<<setprecision(15);
int T=1;
cin>>T;
for (int t = 1; t <= T; ++t)
{
cout << "Case #" << t << ": ";
int n;
cin >> n;
vector G(n+1, vector<int>());
for (int i=1; i<n; ++i)
{
int x, y;
cin >> x >> y;
G[x].push_back(y);
G[y].push_back(x);
}
int ans=0;
vector f(n+1, vector<ll>()), tag_add(n+1, vector<ll>()), tag_mul(n+1, vector<ll>());
vector<int> pos(n+1), ml(n+1);
function<void(int, int)> dfs = [&](int x, int y) -> void
{
pos[x] = x; ml[x] = 1;
for (auto z : G[x]) if (z != y)
{
dfs(z, x);
if (ml[z] + 1 > ml[x]) ml[x] = ml[z] + 1, pos[x] = pos[z];
}
if (x == 1)
{
ans = 1;
for (auto z : G[x])
{
ll ta = 0, tm = 1, Z = pos[z];
f[Z].push_back(0), tag_add[Z].push_back(1), tag_mul[Z].push_back(1);
reverse(all(f[Z]));
reverse(all(tag_add[Z]));
reverse(all(tag_mul[Z]));
for (int i = 0; i <= ml[z]; ++i)
{
f[Z][i] = ((f[Z][i] * tag_mul[Z][i] + tag_add[Z][i]) % p * tm + ta) % p;
ta = (tag_add[Z][i] * tm + ta) % p;
tm = (tm * tag_mul[Z][i]) % p;
tag_add[Z][i] = 0, tag_mul[Z][i] = 1;
}
// cerr << "son : " << z << "\n";
// for (int i = 0; i <= ml[z]; ++i) cerr << f[Z][i] << " "; cerr << "\n";
}
for (auto z : G[x]) ans = ans * f[pos[z]].back() % p;
vector<ll> zero(ml[x]), pro(ml[x], 1), tmp_mul(ml[x], 1), tmp_zero(ml[x], 0);
for (auto z : G[x])
{
int Z = pos[z];
for (int i = 0; i <= ml[z]; ++i)
{
if (f[Z][i]) pro[i] = pro[i] * f[Z][i] % p;
else ++zero[i];
}
if (ml[z] + 1 < ml[x])
{
if (f[Z][ml[z]]) tmp_mul[ml[z] + 1] = tmp_mul[ml[z] + 1] * f[Z][ml[z]] % p;
else ++tmp_zero[ml[z] + 1];
}
}
ll _tmp_mul = 1, _tmp_zero = 0;
for (int i = 0; i < ml[x]; ++i)
{
pro[i] = pro[i] * tmp_mul[i] % p * _tmp_mul % p; _tmp_mul = _tmp_mul * tmp_mul[i] % p;
zero[i] = (zero[i] + _tmp_zero + tmp_zero[i]) % p; _tmp_zero = (_tmp_zero + tmp_zero[i]) % p;
}
for (auto z : G[x])
{
int Z = pos[z];
for (int i=1; i<=ml[z]; ++i)
{
ll g = (f[Z][i] + (p - f[Z][i-1])) % p;
if (!g) continue;
if (zero[i-1] - (f[Z][i-1]==0) == 0)
{
ll num = pro[i-1];
if (f[Z][i-1]) num = num * fpow(f[Z][i-1]) % p;
ans = (ans + (p - g * num % p)) % p;
}
}
}
}
else
{
int X = pos[x];
f[X].push_back(0), tag_add[X].push_back(1), tag_mul[X].push_back(1);
assert(ml[x] == f[X].size());
for (auto z : G[x]) if (z != y && pos[z] != pos[x])
{
ll ta = 0, tm = 1, Z = pos[z];
f[Z].push_back(0), tag_add[Z].push_back(1), tag_mul[Z].push_back(1);
reverse(all(f[Z]));
reverse(all(tag_add[Z]));
reverse(all(tag_mul[Z]));
for (int i = 0; i <= ml[z]; ++i)
{
f[Z][i] = ((f[Z][i] * tag_mul[Z][i] + tag_add[Z][i]) % p * tm + ta) % p;
ta = (tag_add[Z][i] * tm + ta) % p;
tm = (tm * tag_mul[Z][i]) % p;
tag_add[Z][i] = 0, tag_mul[Z][i] = 1;
}
ta = 0, tm = 1;
for (int i = 0; i <= ml[z]; ++i)
{
int j = ml[x] - 1 - i;
f[X][j] = ((f[X][j] * tag_mul[X][j] + tag_add[X][j]) % p * tm + ta) % p;
ta = (tag_add[X][j] * tm + ta) % p;
tm = (tm * tag_mul[X][j]) % p;
tag_add[X][j] = 0, tag_mul[X][j] = 1;
f[X][j] = f[X][j] * f[Z][i] % p;
}
if (ml[x] > ml[z] + 1)
{
int j = ml[x] - 1 - (ml[z] + 1);
ta = (tag_add[X][j] * tm + ta) % p;
tm = (tm * tag_mul[X][j]) % p;
ta = ta * f[Z][ml[z]] % p;
tm = tm * f[Z][ml[z]] % p;
tag_add[X][j] = ta;
tag_mul[X][j] = tm;
}
}
}
};
dfs(1, 0);
cout << ans << "\n";
}
}
致虚极,守静笃,万物并作,吾以观其复