for (int id = 1; id < n; id++) { int u = read(), v = read(); w[id] = read(); E[u].emplace_back(v, id); E[v].emplace_back(u, id); }
init();
vector<vector<int>> vec(n); for (int id = 1; id < n; id++) { int v = son[id]; vec[min(siz[v], n - siz[v])].push_back(id); }
vector<vector<tuple<int, int, int>>> que(n); for (int qid = 0; qid < q; qid++) { int id = read(), e = read(), k = read(); que[k].emplace_back(id, e, qid); }
vector<ll> ans(q); for (int k = 1; k < n; k++) { for (auto& [id, e, qid] : que[k]) { int old = w[id]; if (old) change(id, e); ans[qid] = get(); change(id, old); } for (auto& id : vec[k]) { change(id, 0); } }
for (int i = 0; i < q; i++) { printf("%lld\n", ans[i]); }
int n; cin >> n; vector<vector<int>> E(n); for (int u = 1; u < n; ++u) { int p = read(); p--; E[p].push_back(u); }
vector<int> mn(n), siz(n); auto dfs1 = [&](thisauto&& self, int u) -> void { mn[u] = u; siz[u] = 1; for (auto& v : E[u]) { self(v); mn[u] = min(mn[u], mn[v]); siz[u] += siz[v]; } }; dfs1(0);
for (int u = 0; u < n; ++u) { sort(E[u].begin(), E[u].end(), [&](constint& x, constint& y) { return mn[x] < mn[y]; // 保证字典序最小 }); }
int now = 0; vector<pair<int, int>> res(n); auto dfs2 = [&](thisauto&& self, int u, int d) -> void { int t = siz[u] - 1; for (auto& v : E[u]) { t -= siz[v]; self(v, t + d); } res[u] = { ++now, siz[u] + d }; }; dfs2(0, 0);
for (auto& [a, b] : res) { cout << a << " " << b << " "; } cout << "\n";
int n; cin >> n; vector<vector<int>> E(n); vector<int> deg(n);
for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; u--, v--; E[u].push_back(v); E[v].push_back(u); deg[u]++, deg[v]++; }
for (int u = 0; u < n; ++u) { if (deg[u] != 2) continue; int sum = 0; for (auto v : E[u]) { // 不能加引用& if (deg[v] == 2) { if (E[v][0] == u) v = E[v][1]; else v = E[v][0]; sum++; } sum += deg[v]; } if (sum == n - 1) { cout << "Yes\n"; return; } } cout << "No\n";
2024 牛客多校 4F - Good Tree
[[…/contests/2024牛客多校/2024-07-25:2024牛客暑期多校训练营4#F - Good Tree(138 + 40)|2024-07-25:2024牛客暑期多校训练营4]]
题意 对树上节点u,定义f(u)=∑d(u,v)。给定x,求满足如下条件的n 的最小值:
∃u,v,s.t.f(u)−f(v)=x。
思路 链状最优,二分答案,特判偶数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
ull n = read(); ull l = 1, r = 2e9 + 1, m; auto check = [&](ull x) { if (x & 1) { x >>= 1; return x * x >= n; } else { x >>= 1; return x * x - x >= n; } }; while (l <= r) check(m = l + r >> 1) ? r = m - 1 : l = m + 1; if ((!(l & 1)) && (n & 1)) { l++; } printf("%llu\n", l);
constexprint N = 1e5 + 10; constexprint MOD = 1e9 + 7;
vector<int> E[N]; ll w[N], dep[N]; int c, deg[N], lst[N]; voiddfs(int u, int p = 0){ // 树直径板子 lst[u] = p; for (auto& v : E[u]) { if (v != p) { dep[v] = dep[u] + w[v]; if (dep[v] > dep[c]) c = v; dfs(v, u); } } }
voideachT(){ int n = read(), m = read(); for (int i = 1; i <= n; i++) { E[i].clear(); deg[i] = 0; lst[i] = 0; } // init c = 0;
if (n == 1) { printf("1\n"); return; }
for (int i = 2; i <= n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); deg[u]++, deg[v]++; // 度数 }
ll poww; if (m > 50) poww = 0x3f3f3f3f; else poww = (1ll << m) - 2; for (int i = 1; i <= n; i++) { w[i] = deg[i] + (deg[i] - 1ll) * poww; }
// 找到s-t路径上所有点 vector<int> vis(n), from(n, -1), path; auto dfs = [&](thisauto&& self, int u, int p) { if (u == t) { while (u != -1) { path.push_back(u); vis[u] = 1; u = from[u]; } return; }
for (auto v : E[u]) { if (v == p) continue; from[v] = u; self(v, u); } }; dfs(s, -1);
constint m = path.size();
// 从s-t路径上每个点出发,找到最远的点 auto dfs2 = [&](thisauto&& self, int u, int p) -> int { int d = 0; for (auto v : E[u]) { if (v == p || vis[v]) continue; d = max(d, self(v, u) + 1); } return d; }; vector<int> dep(m); for (int i = 0; i < m; i++) { dep[i] = dfs2(path[i], -1); }
// 博弈 vector<int> a(m), b(m); for (int i = 0; i < m; i++) { a[i] = dep[m - 1 - i] + i; b[i] = dep[i] + i; }
RMQ A(a), B(b); for (int i = 0; i < (m + 1) / 2; i++) { if (a[i] > B(i, m - i - 1)) { cout << "Alice" << endl; return; } if (i < m / 2 && b[i] >= A(i + 1, m - i - 1)) { cout << "Bob" << endl; return; } } assert(false);
思路 如果猫图由多个连通块构成,那么每个连通块至少要有一只猫咪。分别考虑每个连通块,设某个连通块的点集为 U 。若狗图中有某条边连接了 U 中的两个点,且猫图中不含有这条边,那么这个连通块需要 2 只猫咪,否则需要 1 只猫咪。代码极其简单,此处省略。
树和博弈 CF-1404B
题意 树上博弈。两人从起始点a,b 轮流跳,每次跳跃上界为da,db。若 A 和 B 重合,则 A 胜,否则在足够长的时间内都不能重合,则 B 胜。判断胜负。([[…/数学/博弈论#J. 树和博弈 CF-1404B]])
1 2 3 4 5 6 7
bool ans; if (getd(a, b) <= da) ans = 1; // 一步就死 elseif (da >= db) ans = 1; // A 的跳远更牛 elseif (d <= 2 * da) ans = 1; // A 全覆盖 elseif (db >= 2 * da + 1) ans = 0; // B 来回跳跃 else ans = 1; printf("%s\n", ans ? "Alice" : "Bob");
合法 DFS 序与合法 BFS 序
CF 的 EPIC August 考察了合法 DFS 序,想到今年北京市赛的合法 BFS 序(还没有补题),因此写了这篇总结。
vector<unordered_map<int, int>> E(n+1); // 为方便查询 用unordered_map代替vector存图 for (int u = 2; u <= n; ++u) { int p = read(); E[p][u] = 1; }
for (int q = read(); q--; ) { vector<int> dfn(n+1), vis(n+1, 0); for (int i = 0; i < n; i++) { dfn[i] = read(); }
int id = 0, ok = true; auto dfs = [&](thisauto&& self, int u) -> void { vis[u] = 1; int& v = dfn[i++d]; if (E[u].count(v)) self(v); elseif (!E[u].empty()) ok = false; }; if (dfn[0] != 1) ok = false; elsedfs(1);
vector<unordered_map<int, int>> E(n); while (m--) { int u = read(), v = read(); E[u][v] = 1; }
for (int q = read(); q--; ) { vector<int> dfn(n+1), vis(n, 0); for (int i = 0; i < n; i++) { dfn[i] = read(); }
int id = 0, ok = true; auto dfs = [&](thisauto&& self, int u) -> void { vis[u] = 1; int& v = dfn[i++d]; if (E[u].count(v)) { self(v); } elsefor (auto& [v, _] : E[u]) { if (!vis[v]) ok = false; } }; while (id < n) { int& u = dfn[id]; if (!vis[u]) dfs(u); }
voideachT(){ int n = read(), q = read(); for (int u = 2; u <= n; ++u) { p[u] = read(); E[p[u]].push_back(u); }
dfs(1);
for (int i = 1; i <= n; i++) { tdfn[i] = read(); }
int res = 0; // 合法总数 vector<int> oks(n+1, 0); // 记录DFS序的i位置是否合法 auto check = [&](int i) { int& u = tdfn[i], & v = tdfn[i+1]; res -= oks[i]; oks[i] = i >= 1 && i < n && getlca(u, v) == p[v]; res += ok; }; // 判断DFS序的i位置是否合法
for (int i = 1; i < n; i++) { check(i); }
while (q--) { int x = read(), y = read(); swap(tdfn[x], tdfn[y]);
#include<cstdio> #include<iostream> #include<algorithm> #include<vector> #include<set> using ll = longlong; using pii = pair<int, int>; usingnamespace std; inline ll read(){ ll S = 0, C = 0; char Y = getchar(); while (Y > 57 || Y < 48) C |= Y == 45, Y = getchar(); while (Y <= 57 && Y >= 48) S = (S << 3) + (S << 1) + Y - 48, Y = getchar(); return C ? -S : S; }
constint N = 3e5 + 10; int tdfn[N], p[N], dfn[N], siz[N]; vector<int> E[N]; voiddfs(int u){ siz[u] = 1; for (auto& v : E[u]) { dfs(v); siz[u] += siz[v]; } }
voideachT(){ int n = read(), q = read(); for (int i = 0; i <= n; i++) { E[i].clear(); }
for (int u = 2; u <= n; u++) { p[u] = read(); E[p[u]].push_back(u); }
dfs(1);
vector<set<pii>> Q(n + 1); for (int i = 1; i <= n; i++) { tdfn[i] = read(); int u = tdfn[i]; dfn[u] = i; Q[p[u]].insert({ i, siz[u] }); }
int res = 0; vector<int> oks(n + 1); auto check = [&](int i) { if (!i)return; if (Q[i].empty()) return; int mn = (*Q[i].begin()).first; int mx = (*Q[i].rbegin()).first, w = (*Q[i].rbegin()).second; res -= oks[i]; oks[i] = dfn[i] != mn - 1 || mx <= dfn[i] || mx > dfn[i] + siz[i] - w; res += oks[i]; };
for (int i = 1; i <= n; i++) { check(i); }
while (q--) { int x = read(), y = read(); int u = tdfn[x], v = tdfn[y];
intmain(){ for (int T = read(); T--; eachT()); return0; }
出栈序列的合法性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
voideachT(){ int siz = read(), n = read(), q = read(); while (q--) { stack<int> stk; int in = 1, ok = 1; for (int i = 1; i <= n; i++) { int out = read(); while (stk.empty() || stk.top() != out) { if (in > n || stk.size() == siz) { ok = 0; break; } stk.push(in); in++; } stk.pop(); } printf("%s\n", ok ? "YES" : "NO"); } }
树上并查集维护优化连边
例 1 有边权的树。求有序三元组(i,j,k) 对数,满足:
i,j,k 是三个不同的点;
i 到j 有路径,i 到k 也有路径;
每条路径中至少有一条幸运边(幸运边:边权是仅仅由4 和7 组成的正整数)。(Lucky Tree CF109C)
vector<pair<int, int>> E[N]; int p[N], dep[N], idx[N], ans[N]; voiddfs(int u){ for (auto& [v, id] : E[u]) { if (v == p[u]) continue; dep[v] = dep[u] + 1; idx[v] = id; // 边的性质嫁接到点上 见树基础 p[v] = u; dfs(v); } }
voideachT(){ int n = read();
for (int i = 1; i < n; i++) { int u = read(), v = read(); E[u].emplace_back(v, i); E[v].emplace_back(u, i); }
dfs(1);
DSU dsu(n);
for (int d = n / 2; d >= 1; --d) { for (int j = d + d; j <= n; j += d) { int u = dsu.find(d), v = dsu.find(j); while (u != v) { if (dep[u] > dep[v]) swap(u, v); ans[idx[v]] = d; dsu.uno(p[v], v); // 合并路径上所有点 v = dsu.find(p[v]); // 遍历路径上所有点 } } }
for (int i = 1; i < n; i++) { printf("%d ", ans[i]); } printf("\n"); }
/// ----------------主函数---------------- voideachT(){ int n = read(); for (int i = 1; i <= n; i++) { int x = read(); if (!x) x = n + 1; // 给森林一个虚拟根节点n+1 E[x].push_back(i); } initlca(n + 1); int q = read(); for (int i = 1; i <= q; i++) { int v = read(), p = read(); int fav = jump(v, p); // v的p级祖先 if (fav == -1) res[i] = 0; // v没有p级祖先 答案是0 else que[fav].push_back({ dep[v],i }); // 存储每个询问 } smt.init(0, n + 1); dfs(n + 1); // 线段树合并 计算答案 for (int i = 1; i <= q; i++) { printf("%d ", res[i]); } }
/// ----------------树+LCA---------------- vector<int> E[N], ksons[N]; int p[N][22], dep[N]; int c[N]; voidinitlca(int u){ for (int i = 1; i <= __lg(dep[u]); i++) p[u][i] = p[p[u][i - 1]][i - 1]; for (auto& v : E[u]) { if (v == p[u][0]) continue; dep[v] = dep[u] + 1; p[v][0] = u; initlca(v); } } intjump(int v, int k){ k = dep[v] - k; if (k < 0) return-1; while (dep[v] > k) v = p[v][__lg(dep[v] - k)]; return v; } // v的k级祖先
/// ----------------线段树合并---------------- SMT<info> smt; int rt[N], res[N]; voiddfs(int u){ smt.modify(c[u], 1, rt[u]); // 添加u的颜色 for (auto& v : E[u]) { if (v == p[u][0]) continue; dfs(v); smt.merge(rt[u], rt[v]); } for (auto& c : ksons[u]) { smt.modify(c, -1, rt[u]); // 删除u的k+1层儿子的颜色 } res[u] = smt.query(smt.L, smt.R, rt[u]).sum; // 查询u的子树的颜色数 }
/// ----------------主函数---------------- voideachT(){ int n = read(), k = read(); for (int i = 1; i <= n; i++) { c[i] = read(); } for (int i = 1; i < n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); } // 统计每个节点的k+1层儿子的颜色 initlca(1); for (int i = 1; i <= n; i++) { int x = jump(i, k + 1); if (x != -1) ksons[x].push_back(c[i]); } smt.init(1, n); dfs(1); for (int q = read(); q--; ) { int x = read(); printf("%d\n", res[x]); } }
/// ----------------线段树---------------- structinfo { int mx{ 0 }; int id{ 0 }; voidapply(const info& o)& { mx += o.mx; id = o.id; } friend info operator + (const info& l, const info& r) { if (l.mx >= r.mx) return l; elsereturn r; } };
/// ----------------线段树合并---------------- vector<int> E[N]; int dep[N]; SMT<info> smt; int res[N];
voiddfs(int u, int p){ smt.modify(dep[u], { 1, dep[u] }, u); for (auto& v : E[u]) { if (v == p) continue; dep[v] = dep[u] + 1; dfs(v, u); smt.merge(u, v); } res[u] = smt.query(dep[u], smt.R, u).id - dep[u]; }
/// ----------------主函数---------------- voideachT(){ int n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); } smt.init(0, n); dfs(1, 0); for (int i = 1; i <= n; i++) { printf("%d\n", res[i]); } }
/// ----------------主函数---------------- voideachT(){ int n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); } for (int i = 1; i <= n; i++) { w[i] = read(); } smt.init(0, 1e6); init(1, 0); dfs(1, 0); ull anss = 0; for (int i = 1; i <= n; i++) { anss ^= (2 * ans[i]); } printf("%llu\n", anss); }
voiddfs(int u, int p){ smt.modify(w[u], { 1, (ull)w[u] * w[u] }, u); sum1[u] += (ull)w[u] * w[u]; sum2[u] += w[u]; for (auto& v : E[u]) { if (v == p) continue; dfs(v, u); sum1[u] += sum1[v]; sum2[u] += sum2[v]; smt.merge(sum1[u], u, v); } ans[u] = sum1[u] - sum2[u] * sum2[u]; }
/// ----------------主函数---------------- voideachT(){ int n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); } for (int i = 1; i <= n; i++) { w[i] = read(); } smt.init(0, 1e6); dfs(1, 0); ull anss = 0; for (int i = 1; i <= n; i++) { anss ^= ans[i]; } printf("%llu\n", anss); }
structmark { ll asn{ -1 }; voidapply(const mark& d, int s){ if (~d.asn) asn = d.asn; } }; structinfo { ll val{ 0 }; voidapply(const mark& d, int s){ if (~d.asn) val = d.asn; } voidapply(const info& d){ val |= d.val; } friend info operator + (const info& l, const info& r) { return { l.val | r.val }; } };
voideachT(){ int n = read(), q = read(), r = 1;
for (int u = 1; u <= n; u++) { w[u] = 1ll << read(); }
for (int i = 2; i <= n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); }
dfs(r); top[r] = r, dfs2(r);
SMT<info, mark> smt; smt.init(1, n);
for (int i = 1; i <= n; i++) { smt.modify_node(i, { w[i] }); }
while (q--) { int op = read(); if (op == 1) { ll u = read(), d = 1ll << read(); smt.modify_subtree(u, { d }); } else { int u = read(); auto res = smt.query_subtree(u); printf("%d\n", __builtin_popcountll(res.val)); } } }
vector<int> E[N]; int arr[N]; int p[N], dep[N], siz[N], top[N]; int efn[N], efnR[N], eseq[N], eunix;
voiddfs(int u){ siz[u] = 1; for (auto& v : E[u]) { if (v == p[u]) continue; p[v] = u; dep[v] = dep[u] + 1; dfs(v); siz[u] += siz[v]; if (siz[v] > siz[E[u][0]]) swap(v, E[u][0]); } }
voiddfs2(int u){ efn[u] = ++eunix, eseq[eunix] = u; for (auto& v : E[u]) { if (v == p[u]) continue; top[v] = v == E[u][0] ? top[u] : v; dfs2(v); } efnR[u] = ++eunix, eseq[eunix] = u; }
// u,v的最近公共祖先 intgetlca(int u, int v){ while (top[u] != top[v]) { if (dep[top[u]] > dep[top[v]]) u = p[top[u]]; else v = p[top[v]]; } return dep[u] > dep[v] ? v : u; }
int B; structQUE { int lca; // need lca or not int ql, qr, id; booloperator<(const QUE& b) const { return ql / B != b.ql / B ? ql < b.ql : (ql / B & 1 ? qr < b.qr : qr > b.qr); } };
int cnt[N], now; // 颜色数量 int cnt2[N]; // 每种颜色出现次数 偶数次不记 voidadd(int p){ // p是欧拉序编号 cnt2[eseq[p]]++; // eseq[p]是树的编号 if (cnt[arr[eseq[p]]] == 0) now++; cnt[arr[eseq[p]]] += cnt2[eseq[p]] & 1 ? 1 : -1; if (cnt[arr[eseq[p]]] == 0) now--; } voiddel(int p){ if (cnt[arr[eseq[p]]] == 0) now++; cnt2[eseq[p]]--; cnt[arr[eseq[p]]] -= cnt2[eseq[p]] & 1 ? -1 : 1; if (cnt[arr[eseq[p]]] == 0) now--; }
voideachT(){ int n = read(); int q = read(); B = sqrt(n);
vector<int> alls; for (int i = 1; i <= n; i++) { arr[i] = read(); alls.push_back(arr[i]); } sort(alls.begin(), alls.end()); alls.erase(unique(alls.begin(), alls.end()), alls.end()); for (int i = 1; i <= n; i++) { arr[i] = lower_bound(alls.begin(), alls.end(), arr[i]) - alls.begin(); }
for (int i = 1; i < n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); }
dfs(1); top[1] = 1, dfs2(1);
vector<QUE> que(q); vector<int> ans(q); for (int i = 0; i < q; i++) { int u = read(), v = read(); if (getlca(u, v) == u orgetlca(u, v) == v) { if (getlca(u, v) == v) swap(u, v); que[i].ql = efn[u], que[i].qr = efn[v]; que[i].lca = 0; } else { que[i].ql = efnR[u], que[i].qr = efn[v]; que[i].lca = getlca(u, v); } que[i].id = i; } sort(que.begin(), que.end());
int cl = 1, cr = 0; for (auto& [lca, ql, qr, id] : que) { while (cl > ql) add(--cl); while (cr < qr) add(++cr); while (cl < ql) del(cl++); while (cr > qr) del(cr--); if (lca) add(efn[lca]); ans[id] = now; if (lca) del(efn[lca]); }
for (int i = 0; i < q; i++) { printf("%d\n", ans[i]); } }
#include<iostream> #include<algorithm> #include<vector> using pii = pair<int, int>; using piii = tuple<int, int, int>;
intgcd(int a, int b){ return b ? gcd(b, a % b) : a; } intlcm(int a, int b){ return1ll * a * b / gcd(a, b); }
constexprint N = 1e5 + 8; vector<int> divisor[N]; vector<pii> pairs[N]; voidinitlcm(){ for (int i = 1; i < N; i++) { for (int L = i; L < N; L += i) divisor[L].emplace_back(i); } for (int i = 1; i < N; i++) { for (int L = i; L < N; L += i) { for (int& j : divisor[L]) { if (i >= j andlcm(i, j) == L) pairs[L].emplace_back(i, j); } } } }
vector<int> E[N]; int pa[N], hson[N], siz[N], dep[N], top[N]; int unix, dfn[N], dfnR[N], tdfn[N];
voiddfs1(int u, int p = 0){ int mx = 0; dep[u] = dep[p] + 1; siz[u] = 1; dfn[u] = ++unix, tdfn[unix] = u; for (auto& v : E[u]) { if (v == p) continue; dfs1(v, u); pa[v] = u; siz[u] += siz[v]; if (siz[v] > mx) hson[u] = v, mx = siz[v]; } dfnR[u] = unix; }
voiddfs2(int u, int p = 0){ if (hson[u]) { top[hson[u]] = top[u]; dfs2(hson[u], u); } for (auto& v : E[u]) { if (v == p || v == hson[u]) continue; top[v] = v; dfs2(v, u); } }
intgetlca(int u, int v){ while (top[u] != top[v]) { if (dep[top[u]] > dep[top[v]]) u = pa[top[u]]; else v = pa[top[v]]; } return dep[u] > dep[v] ? v : u; }
structBIT { vector<int> t; int N; BIT(int n) { N = n + 1; t.resize(N); } voidupdate(int p, int x){ while (p < N) t[p] += x, p += p & -p; } intquery(int p){ int res = 0; while (p >= 1) res += t[p], p -= p & -p; return res; } intquery(int l, int r){ returnquery(r) - query(l - 1); } };
voideachT(){ int n; cin >> n;
unix = 0; for (int i = 0; i <= n; i++) { E[i].clear(); pa[i] = hson[i] = siz[i] = dep[i] = top[i] = 0; dfn[i] = dfnR[i] = tdfn[i] = 0; } // RE
for (int i = 1; i < n; i++) { int u, v; cin >> u >> v;
E[u].emplace_back(v); E[v].emplace_back(u); }
dfs1(1); top[1] = 1, dfs2(1);
int q; cin >> q;
vector<piii> ask(q); vector<int> ans(q); for (int i = 0; i < q; i++) { int r, x; cin >> r >> x; ask[i] = { x, r, i }; } sort(ask.begin(), ask.end()); // 按 x 升序
BIT bit(n);
int it = 0; for (int L = 1; L < N; ++L) { for (auto& [u, v] : pairs[L]) { if (u > n or v > n) continue; bit.update(dfn[getlca(u, v)], u == v ? 1 : 2); } while (it < q) { auto& [x, r, id] = ask[it]; if (x != L) break; ans[id] = bit.query(dfn[r], dfnR[r]); i++t; } }
for (int i = 0; i < q; i++) { cout << ans[i] << " \n"[i == q - 1]; } }
int p[N], hson[N], dep[N], siz[N], top[N]; int dfn[N], dfnR[N], tdfn[N], dunix; int L[N], R[N], eunix; int tim[N]; voiddfs(int u){ siz[u] = 1; dep[u] = dep[p[u]] + 1; L[u] = ++eunix, tim[eunix] = u; dfn[u] = ++dunix, tdfn[dunix] = u; for (auto& v : E[u]) { if (v == p[u]) continue; p[v] = u; dfs(v); siz[u] += siz[v]; if (siz[v] > siz[hson[u]]) hson[u] = v; } R[u] = ++eunix, tim[eunix] = u; dfnR[u] = dunix; }
voiddfs2(int u){ if (hson[u]) { top[hson[u]] = top[u]; dfs2(hson[u]); } for (auto& v : E[u]) { if (v == p[u] || v == hson[u]) continue; top[v] = v; dfs2(v); } }
intgetlca(int u, int v){ while (top[u] != top[v]) { if (dep[top[u]] > dep[top[v]]) u = p[top[u]]; else v = p[top[v]]; } return dep[u] > dep[v] ? v : u; }
structSMT1 { int pcnt; staticint L, R, rt; structinfo { int Lmn, Lmx, Rmn, Rmx; int l, r; } t[N << 2];
voidinit(int l, int r){ for (int i = 0; i <= pcnt; i++) init(i); pcnt = 0, rt = 0; L = l, R = r; }
voidmodify(int x, int d, int& p = rt, int cl = L, int cr = R){ if (!p) p = ++pcnt, init(p); if (cl == cr) { t[p].mx = t[p].mn = d; return; } if (x <= mid) modify(x, d, lson); if (mid < x) modify(x, d, rson); returnpush_up(p); }
info query(int l, int r, int& p = rt, int cl = L, int cr = R){ if (l <= cl && cr <= r) return t[p]; if (r <= mid) returnquery(l, r, lson); if (mid < l) returnquery(l, r, rson); info res; push_up(res, query(l, r, lson), query(l, r, rson)); return res; }
info query_path(int u, int v){ info res = { 0, 1000000000 }; while (top[u] != top[v]) { if (dep[top[u]] > dep[top[v]]) { push_up(res, res, query(dfn[top[u]], dfn[u])); u = p[top[u]]; } else { push_up(res, res, query(dfn[top[v]], dfn[v])); v = p[top[v]]; } } if (dep[u] > dep[v]) { push_up(res, res, query(dfn[v], dfn[u])); } else { push_up(res, res, query(dfn[u], dfn[v])); } return res; } }; int SMT2::L, SMT2::R, SMT2::rt; SMT2 smt2;
voideachT(){ int n = read(); eunix = dunix = 0; for (int u = 1; u <= n; u++) { E[u].clear(); L[u] = R[u] = tim[u] = 0; dfn[u] = dfnR[u] = tdfn[u] = 0; p[u] = hson[u] = dep[u] = siz[u] = top[u] = 0;
w[u] = read(); }
for (int i = 2; i <= n; i++) { int u = read(), v = read(); E[u].push_back(v); E[v].push_back(u); }
dfs(1); top[1] = 1, dfs2(1);
smt1.init(1, n); smt2.init(1, n);
for (int u = 1; u <= n; u++) { smt1.modify(w[u], make_pair(L[u], R[u])); smt2.modify(dfn[u], w[u]); }
int q = read(); while (q--) { int op = read(); if (op == 1) { int u = read(), v = read(); // 交换u和v的点权 swap(w[u], w[v]); smt1.modify(w[u], make_pair(L[u], R[u])); smt1.modify(w[v], make_pair(L[v], R[v])); smt2.modify(dfn[u], w[u]); smt2.modify(dfn[v], w[v]); } else { int l = read(), r = read(); auto res1 = smt1.query(l, r); int u = tim[res1.Lmx], v = tim[res1.Rmn]; int lca = getlca(u, v); if (lca == u || lca == v) { u = tim[res1.Lmn], v = tim[res1.Lmx]; lca = getlca(u, v); } auto res2 = smt2.query_path(u, v); if (dep[u] + dep[v] - 2 * dep[lca] == r - l && res2.mx == r && res2.mn == l) { printf("Yes\n"); } else { printf("No\n"); } } } }
signedmain(){ for (int T = read(); T--; eachT()); return0; }
int k, dp[N][K]; ll ans = 0; voiddfs(int u, int p){ for (auto v : E[u]) { if (v == p) continue; dfs(v, u); for (int i = 1; i <= k; i++) ans += dp[v][i - 1] * dp[u][k - i]; for (int i = 1; i <= k; i++) dp[u][i] += dp[v][i - 1]; } dp[u][0] = 1; ans += dp[u][k]; } print(ans);
constexprint K = 1e7 + 8; int ans[K]; voidTDC::cal(int u){ unordered_map<int, int> ttdeps; ttdeps[0] = 1;
for (auto& [w, v] : E[u]) { if (vis[v]) continue; vector<int> deps;
auto dfs = [&](thisauto&& self, int u, int p, int dep) -> void { if (dep >= K) return; deps.push_back(dep); for (auto& [w, v] : E[u]) { if (v == p || vis[v]) continue; self(v, u, dep + w); } };
dfs(v, u, w);
for (auto& dep : deps) { for (auto& [k, v] : ttdeps) { if (dep + k >= K) continue; ans[dep + k] |= v; } } for (auto& dep : deps) { ttdeps[dep] = 1; } } }
voideachT(){ int n = read(), q = read(); tdc.init(n); for (int i = 2; i <= n; i++) { int u = read(), v = read(), w = read(); tdc.add(u, v, w); } tdc.solve(); while (q--) { int u = read(); printf("%s\n", ans[u] ? "Yes" : "No"); } }
constexprint K = 1e7 + 8; vector<int> que, ans; voidTDC::cal(int u){ unordered_map<int, int> ttdeps; ttdeps[0] = 1;
for (auto& [w, v] : E[u]) { if (vis[v]) continue; vector<int> deps;
auto dfs = [&](thisauto&& self, int u, int p, int dep) -> void { if (dep >= K) return; deps.push_back(dep); for (auto& [w, v] : E[u]) { if (v == p || vis[v]) continue; self(v, u, dep + w); } };
dfs(v, u, w);
for (int i = 0; i < que.size(); i++) { if (ans[i]) continue; // 剪枝 避免TLE for (auto& dep : deps) { if (ttdeps.count(que[i] - dep)) { ans[i] = 1; } } } for (auto& dep : deps) { ttdeps[dep] = 1; } } }
voideachT(){ int n = read(), q = read(); tdc.init(n); for (int i = 2; i <= n; i++) { int u = read(), v = read(), w = read(); tdc.add(u, v, w); } que.resize(q), ans.resize(q); for (int i = 0; i < q; i++) { que[i] = read(); } tdc.solve(); for (int i = 0; i < q; i++) { printf("%s\n", ans[i] ? "Yes" : "No"); } }
int k, ans; voidTDC::cal(int u){ unordered_map<int, int> ttdeps; ttdeps[0] = 0; // WA
for (auto& [w, v] : E[u]) { if (vis[v]) continue; unordered_map<int, int> deps;
auto dfs = [&](thisauto&& self, int u, int p, int dep, int len) -> void { if (dep > k) return; if (!deps.count(dep) || deps[dep] > len) { deps[dep] = len; } for (auto& [w, v] : E[u]) { if (v == p || vis[v]) continue; self(v, u, dep + w, len + 1); } };
dfs(v, u, w, 1);
for (auto& [dep, len] : deps) { if (ttdeps.count(k - dep)) { ans = min(ans, ttdeps[k - dep] + len); } } for (auto& [dep, len] : deps) { if (!ttdeps.count(dep) || ttdeps[dep] > len) { ttdeps[dep] = len; } } } }
voideachT(){ int n = read(); k = read(); tdc.init(n); for (int i = 2; i <= n; i++) { int u = read(), v = read(), w = read(); tdc.add(u, v, w); } ans = inf; tdc.solve(); if (ans == inf) ans = -1; printf("%d\n", ans); }
int k; ll ans; voidTDC::cal(int u){ bit.init(); bit.update(1, 1);
for (auto& [w, v] : E[u]) { if (vis[v]) continue;
vector<int> deps;
auto dfs = [&](thisauto&& self, int u, int p, int dep) -> void { if (dep > k) return; deps.push_back(dep); for (auto& [w, v] : E[u]) { if (v == p || vis[v]) continue; self(v, u, dep + w); } };
dfs(v, u, w);
for (auto& dep : deps) { ans += bit.query(k - dep + 1); } for (auto& dep : deps) { bit.update(dep + 1, 1); } } }
voideachT(){ int n = read(); tdc.init(n); for (int i = 2; i <= n; i++) { int u = read(), v = read(), w = read(); tdc.add(u, v, w); } k = read(); ans = 0; tdc.solve(); printf("%lld\n", ans); }
int val[N]; int ans; voidTDC::cal(int u){ auto solve = [&](int x, int u) { auto dfs = [&](thisauto&& self, int x, int u, int p) -> int { int res = 1; for (auto& [w, v] : E[u]) { if (v == p || vis[v]) continue; if (val[v] % x) continue; // 如果v点的值不是x的倍数 res = max(res, self(x, v, u) + 1); } return res; };
// 找两个最大的dp int mx1 = 0, mx2 = 0; for (auto& [w, v] : E[u]) { if (vis[v]) continue; if (val[v] % x) continue; // 如果v点的值不是x的倍数 int res = dfs(x, v, u); if (res > mx1) mx2 = mx1, mx1 = res; elseif (res > mx2) mx2 = res; } ans = max(ans, mx1 + mx2 + 1); };
auto tmp = val[u]; for (int i = 2; i * i <= tmp; i++) { if (tmp % i == 0) { solve(i, u); while (tmp % i == 0) tmp /= i; } } if (tmp > 1) solve(tmp, u); }
voideachT(){ int n = read(); for (int i = 1; i <= n; i++) { val[i] = read(); } tdc.init(n); for (int i = 2; i <= n; i++) { int u = read(), v = read(); tdc.add(u, v, 1); } tdc.solve(); printf("%d\n", ans); }
树上倍增(树上二分)与差分
模板 2:树上倍增(树上二分)与差分
题意 树,根为 1,有边权有点权。问对于每个顶点 u,子树中有多少个顶点 v 满足 d(v,u)⩽wv。数据范围:n⩽2×105,w⩽109。(CF739B)
voiddfs(int u){ for (int i = 1; i <= Log2[dep[u]]; i++) p[u][i] = p[p[u][i - 1]][i - 1]; for (auto& [w, v] : E[u]) { if (v == p[u][0]) continue; dep[v] = dep[u] + 1; p[v][0] = u; val[v] = val[u] + w; // 将边权存储在子节点上 dfs(v); } }
intgetlca(int u, int v){ if (dep[u] > dep[v]) swap(u, v); // -> dep[u]<=dep[v] while (dep[u] != dep[v]) v = p[v][Log2[dep[v] - dep[u]]]; // -> dep[u]==dep[v] if (u == v) return u; for (int d = Log2[dep[u]]; d >= 0; --d) { if (p[u][d] != p[v][d]) u = p[u][d], v = p[v][d]; } // 一步一步向上跳 return p[u][0]; }
intmain(){ for (int i = 2; i < N; i++) Log2[i] = Log2[i >> 1] + 1;
int n, q; cin >> n >> q;
for (int i = 1; i <= n; i++) { int x; cin >> x;
int cnt2 = 0, cnt5 = 0; while (x && x % 2 == 0) x /= 2, cnt2 += 1; while (x && x % 5 == 0) x /= 5, cnt5 += 1; node w = { cnt2,cnt5,!x }; wpos[i] = w; }
for (int i = 2; i <= n; i++) { int u, v; double wd; cin >> u >> v >> wd;
int fz = (int)(wd * 10000), fm = 10000; // 分子分母 int cnt2 = 0, cnt5 = 0; while (fz && fz % 2 == 0) fz /= 2, cnt2 += 1; while (fz && fz % 5 == 0) fz /= 5, cnt5 += 1; while (fm && fm % 2 == 0) fm /= 2, cnt2 -= 1; while (fm && fm % 5 == 0) fm /= 5, cnt5 -= 1;