voiddfs(int u, int f){ fa[u][0] = f; dep[u] = dep[f] + 1;
for (int i = 1; i < 13; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int to : e[u]) { if (to == f) continue; dfs(to, u); } }
intLCA(int x, int y){ if (dep[x] < dep[y]) swap(x, y);
int gap = dep[x] - dep[y]; for (int i = 0; i < 13; ++i) { if (!gap) break; if (gap & 1) x = fa[x][i]; gap >>= 1; } if (x == y) return x; for (int i = 12; i >= 0; --i) { if (fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; }
boolonPath(int x, int u, int v){ returndis(x, u) + dis(x, v) == dis(u, v); }
intexgcd(int a, int b, int& x, int& y){ if (!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, x, y); int tmp = x; x = y, y = tmp - a / b * y; return d; }
longlongwork(int a, int b, int p, int q){ int c = q - p; c = (c % b + b) % b; int x, y; int d = exgcd(a, b, x, y); if (c % d) return inf; int t1 = b / d; longlong minPosSol = ((x * c / d) % t1 + t1) % t1; return minPosSol * a + p; }
voidcalcOnPoint(int i){ if (onPath(i, sa, ta) && onPath(i, sb, tb)) { int a = 2 * dis(sa, ta), b = 2 * dis(sb, tb); int p1 = dis(sa, i); int p2 = dis(sa, ta) + dis(i, ta); int q1 = dis(sb, i); int q2 = dis(sb, tb) + dis(i, tb); longlong sol1 = work(a, b, p1, q1); longlong sol2 = work(a, b, p1, q2); longlong sol3 = work(a, b, p2, q1); longlong sol4 = work(a, b, p2, q2); longlong minSol = min(min(sol1, sol2), min(sol3, sol4));
if (minSol < minTime) { minTime = minSol; ans = i; } } }
voidsolve(){ cin >> n >> m;
for (int i = 1; i <= n; ++i) { e[i].clear(); dep[i] = 0; for (int j = 0; j < 13; ++j) fa[i][j] = 0; }
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);
while (m--) { cin >> sa >> ta >> sb >> tb;
ans = -1; minTime = inf;
int LCAa = LCA(sa, ta), i = sa; while (i != LCAa) { calcOnPoint(i); i = fa[i][0]; } i = ta; while (i != LCAa) { calcOnPoint(i); i = fa[i][0]; } calcOnPoint(LCAa);
string getCore(string str){ int i = 0, j = 1, k = 0; while (k < m && i < m && j < m) { char fir = str[(i + k) % m], sec = str[(j + k) % m]; if (fir == sec) ++k; else { (fir > sec) ? (i += (k + 1)) : (j += (k + 1)); k = 0; if (i == j) ++j; } } i = min(i, j); string res = ""; for (int k = 0; k < m; ++k) res += str[(i + k) % m]; return res; }
intmain(){
ios::sync_with_stdio(false); cin.tie(0);
int tt; cin >> tt;
while (tt--) { cin >> n >> m;
int cnt = 0; string str; for (int i = 1; i <= n; ++i) { cin >> str; string core = getCore(str); if (!Hash.count(core)) Hash[core] = ++cnt; id[i] = Hash[core]; }
int q; cin >> q; while (q--) { int x, y; cin >> x >> y; cout << (id[x] == id[y] ? "Yes" : "No") << endl; }
Hash.clear(); for (int i = 1; i <= n; ++i) id[i] = 0; }
return0; }
Assertion
唯一的一道水题。抽屉原理。
Play on Tree
好题,一道题覆盖了博弈论 + 换根两个知识点。哪天找个时间写下关于 NIM
游戏,SG 定理的东西,这些概念确实很有趣,但也很烧脑。
intqpow(int x, int y){ int res = 1; while (y) { if (y & 1) res = 1LL * res * x % mod; y >>= 1; x = 1LL * x * x % mod; } return res; }
intdfs1(int u, int fa){ for (int to : e[u]) { if (to == fa) continue; SG[u] ^= (dfs1(to, u) + 1); } return SG[u]; }
voiddfs2(int u, int fa){ if (fa != 0) { g[u] = (SG[fa] ^ (SG[u] + 1) ^ g[fa]) + 1; } for (int to : e[u]) { if (to == fa) continue; dfs2(to, u); } }
intsolve(){ cin >> n; for (int i = 1; i <= n; ++i) { e[i].clear(); SG[i] = g[i] = 0; } for (int i = 1; i < n; ++i) { int u, v; cin >> u >> v; e[u].push_back(v); e[v].push_back(u); }
dfs1(1, 0); dfs2(1, 0);
int ans = 0; if (SG[1] > 0) ans = 1; for (int i = 2; i <= n; ++i) { if (SG[i] ^ g[i]) ++ans; }
return1LL * ans * qpow(n, mod - 2) % mod; }
intmain(){
ios::sync_with_stdio(false); cin.tie(0);
int tt; cin >> tt; while (tt--) { cout << solve() << endl; }