1 条题解
-
0
自动搬运
来自洛谷,原作者为

bluewindde
d2673e765642345244b4fb8edf1add1cf8425a4b7743f39b020d410d67ce15b0搬运于
2025-08-24 23:11:31,当前版本为作者最后更新于2025-03-28 19:17:42,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
学完 FHQ 三天后这题出现在模拟赛里。
生成失败就是删点,答案是每个连通块内粒子的个数除以二下取整的和。
设 表示访问和回溯时的 dfn 序。
维护每个连通块内的粒子,删点操作就是把粒子分到新产生的连通块内,先减掉原来的贡献,加上新连通块的贡献即可。使用上述 dfn 序 + FHQ-Treap 容易完成该操作。具体而言,设删除点 ,先把 的 分裂出来,然后用同样方法分裂给 的子树,剩余部分分给原来的连通块根。
维护每个点属于哪个连通块用线段树容易完成,插入也就容易了。时间复杂度 。
#include <chrono> #include <iostream> #include <random> #include <vector> using namespace std; namespace particles { int n; vector<int> vec[200005]; int f[200005]; int dfn[200005], dfn_clock; int nfd[200005]; int low[200005]; static inline void dfs(int u, int fa) { f[u] = fa; nfd[dfn[u] = ++dfn_clock] = u; for (auto v : vec[u]) { if (v == fa) continue; dfs(v, u); } low[u] = dfn_clock; } int rt[200005], cnt; mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count()); struct node { int ls, rs, pri, siz, x; } tr[200005]; static inline int make(int x) { tr[++cnt].pri = (int)rnd(); tr[cnt].siz = 1; tr[cnt].x = x; return cnt; } static inline void pushup(int p) { tr[p].siz = tr[tr[p].ls].siz + tr[tr[p].rs].siz + 1; } static inline void split(int x, int p, int &u, int &v) { if (!p) { u = v = 0; return; } if (dfn[tr[p].x] <= x) u = p, split(x, tr[p].rs, tr[p].rs, v); else v = p, split(x, tr[p].ls, u, tr[p].ls); pushup(p); } static inline int merge(int u, int v) { if (!u || !v) return u | v; if (tr[u].pri < tr[v].pri) { tr[u].rs = merge(tr[u].rs, v); pushup(u); return u; } else { tr[v].ls = merge(u, tr[v].ls); pushup(v); return v; } } int d[800005]; int tag[800005]; static inline void pushtag(int p, int c) { d[p] = max(d[p], c); tag[p] = max(tag[p], c); } static inline void pushdown(int p) { pushtag(p << 1, tag[p]); pushtag(p << 1 | 1, tag[p]); tag[p] = 0; } static inline void build(int s, int t, int p) { if (s == t) { d[p] = 1; return; } int mid = (s + t) >> 1; build(s, mid, p << 1); build(mid + 1, t, p << 1 | 1); } static inline void update(int l, int r, int s, int t, int c, int p) { if (l <= s && r >= t) { pushtag(p, c); return; } int mid = (s + t) >> 1; pushdown(p); if (l <= mid) update(l, r, s, mid, c, p << 1); if (r > mid) update(l, r, mid + 1, t, c, p << 1 | 1); } static inline int query(int x, int s, int t, int p) { if (s == t) return d[p]; int mid = (s + t) >> 1; pushdown(p); if (x <= mid) return query(x, s, mid, p << 1); return query(x, mid + 1, t, p << 1 | 1); } int ans; static inline void initialize(int _n, const vector<int> &_u, const vector<int> &_v) { n = _n; for (int i = 0; i < n - 1; ++i) { int u = _u[i] + 1, v = _v[i] + 1; vec[u].push_back(v); vec[v].push_back(u); } dfs(1, 0); build(1, n, 1); } static inline void enable(int u) { int r = nfd[query(dfn[u], 1, n, 1)]; ans -= tr[rt[r]].siz >> 1; int x; split(dfn[u], rt[r], rt[r], x); rt[r] = merge(rt[r], merge(make(u), x)); ans += tr[rt[r]].siz >> 1; } static inline void disable(int u) { int r = nfd[query(dfn[u], 1, n, 1)]; ans -= tr[rt[r]].siz >> 1; int x, y, z; split(dfn[u], rt[r], rt[r], x); split(low[u], x, y, z); for (auto v : vec[u]) { if (v == f[u]) continue; update(dfn[v], low[v], 1, n, dfn[v], 1); split(low[v], y, rt[v], y); ans += tr[rt[v]].siz >> 1; } rt[r] = merge(rt[r], z); ans += tr[rt[r]].siz >> 1; } } // namespace particles void initialize(int N, vector<int> A, vector<int> B) { particles::initialize(N, A, B); } int generate(int v, bool result) { ++v; if (result) particles::enable(v); else particles::disable(v); return particles::ans; }
- 1
信息
- ID
- 11725
- 时间
- 5000ms
- 内存
- 1024MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者