CF1254D Tree Queries
Tree Queries
题面翻译
给定一棵
给定一个点 和一个权值 ,等概率地选择一个点 ,对每一个点 ,若 在 到 的路径上,则 的权值加上 (权值一开始为 )。 查询 的权值期望,对 取模。
Solution
操作很怪异,所以考虑一下每次操作会对所有点产生什么影响。先选中一个点
那么可以有两种不同思路的暴力,一种修改慢查询快,一种修改快查询慢:
- 考虑对每一个节点
维护一个值 表示当前节点的答案。那么每次修改就是暴力枚举修改节点的每一个子树,然后暴力的加到所有节点的 上。 - 每次修改的时候暴力枚举所有修改过的点,然后根据修改的这个点在询问点的哪一个子树来计算答案。
注意到我们每一次的修改都与当前节点有的子树个数相关,因此对度数根号分治,设一个阈值
对于修改操作,如果当前点是关键点,那么就只把当前点标记上;否则直接暴力枚举所有子树然后处理贡献。注意到处理贡献的时候可以看作是子树加,所以使用树状数组来维护。复杂度是
对于询问操作,先在树状数组中取出非关键点的贡献,然后再暴力枚举所有关键点并计算其贡献。时间复杂度不精细实现是
Code
int N, Q, S;
vector<int> e[_N];
bool crit[_N];
int deg[_N];
vector<int> crl;
int fa[20][_N], dep[_N], siz[_N], dfn[_N], tot;
void dfs(int x, int F) {
fa[0][x] = F, siz[x] = 1, dfn[x] = ++tot, dep[x] = dep[F] + 1;
For(i, 1, 18) fa[i][x] = fa[i-1][fa[i-1][x]];
for (int v: e[x]) if (v ^ F) dfs(v, x), siz[x] += siz[v];
}
int jump(int x, int y) {
for (int tmp = dep[x] - dep[y] - 1, i = 0; tmp; tmp >>= 1, ++i)
if (tmp & 1) x = fa[i][x];
return x;
}
struct Bit {
mint val[_N];
inline int lowbit(int x) {return x & -x;}
void update(int x, mint v) {for (; x <= N; x += lowbit(x)) val[x] += v;}
inline void update(int l, int r, mint v) {update(l, v), update(r + 1, -v);}
mint ask(int x) {mint res = 0; for (; x; x -= lowbit(x)) res += val[x]; return res;}
} bit;
inline bool chk(int x, int y) {return dfn[x] >= dfn[y] && dfn[x] < dfn[y] + siz[y];}
mint inv, val[_N];
void _() {
cin >> N >> Q;
inv = mint(1) / N;
For(i, 2, N) {
int x, y; cin >> x >> y;
e[x].epb(y), e[y].epb(x);
++deg[x], ++deg[y];
}
S = sqrt(N);
For(i, 1, N) if (deg[i] >= S)
crl.epb(i), crit[i] = 1;
Debug("crit:", crl);
dfs(1, 0);
while (Q--) {
int opt, x;
cin >> opt >> x;
if (opt == 1) {
mint d; cin >> d;
if (crit[x]) val[x] += d;
else {
for (int v: e[x]) {
if (fa[0][x] == v) {
mint res = (N - siz[x]) * d * inv;
bit.update(dfn[x], dfn[x] + siz[x] - 1, res);
} else {
mint res = siz[v] * d * inv;
bit.update(1, N, res);
bit.update(dfn[v], dfn[v] + siz[v] - 1, -res);
}
}
bit.update(1, N, d * inv);
}
} else {
mint base = bit.ask(dfn[x]);
for (int c: crl) {
if (x == c) base += val[c];
else if (chk(x, c)) {
int u = jump(x, c);
base += val[c] * (N - siz[u]) * inv;
} else base += val[c] * siz[c] * inv;
}
fmtout("{}\n", base);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步