【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";
	}
}
posted @ 2024-12-10 23:14  PaperCloud  阅读(21)  评论(0编辑  收藏  举报