[GXOI/GZOI2019]旧词
作者:互联网
\(\text{Solution}\)
第一部分参考 \(\text{LNOI2014 LCA}\)
在 \(k=1\) 时完全可行
因为对于每个 \(i\), 根到 \(y\) 的路径之和恰好是 \(dep[lca]\)
但当 \(k>1\) 呢?
此时我们要想办法弄出一个加数的方式,使根到 \(y\) 的路径之和为 \(dep[lca]^k\)
考虑每个点 \(x\) 加上的权值为 \(dep[x]^k-dep[fa[x]]^k\)
此时加起来就是 \(dep[lca]^k\)
那问题来了,怎么快速让 \(i\) 到根的每个点 \(x\) 加上这种的数
发现对于一个点加上的数总是相同的(即 \(dep[x]^k-dep[fa[x]]^k\))
那么我们就可以以这个数为点的系数,加 \(x\) 就相当于这个点加上了 \(f \cdot x\)
打一棵不需要修改系数的线段树即可
\(\text{Code}\)
#include <cstdio>
#define LL long long
using namespace std;
const int N = 5e4 + 5;
const LL P = 998244353;
int n, q, k, h[N], H[N], tot, Tot;
struct edge{int nxt, to;}e[N];
struct node{int nxt, to, id;}Q[N];
inline LL fpow(LL x, LL y)
{
LL res = 1;
for(; y; y >>= 1, x = x * x % P) if (y & 1) res = res * x % P;
return res;
}
int top[N], fa[N], dfn[N], rev[N], siz[N], son[N], dep[N], dfc;
void dfs1(int x)
{
siz[x] = 1;
for(int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
dep[v] = dep[x] + 1, dfs1(v), siz[x] += siz[v];
if (siz[son[x]] < siz[v]) son[x] = v;
}
}
void dfs2(int x, int t)
{
top[x] = t, dfn[x] = ++dfc, rev[dfc] = x;
if (son[x]) dfs2(son[x], t);
for(int i = h[x]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == son[x]) continue;
dfs2(v, v);
}
}
#define ls (p << 1)
#define rs (ls | 1)
LL sum[N * 4], f[N * 4], depk[N * 4], tag[N * 4], ans[N];
void build(int p, int l, int r)
{
if (l == r) return void(f[p] = (depk[rev[l]] - depk[fa[rev[l]]] + P) % P);
int mid = (l + r) >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
f[p] = (f[ls] + f[rs]) % P;
}
inline void pushdown(int p)
{
if (!tag[p]) return;
sum[ls] = (sum[ls] + tag[p] * f[ls] % P) % P, tag[ls] += tag[p];
sum[rs] = (sum[rs] + tag[p] * f[rs] % P) % P, tag[rs] += tag[p];
tag[p] = 0;
}
void modify(int p, int l, int r, int tl, int tr, int v)
{
if (tl <= l && r <= tr)
{
sum[p] = (sum[p] + f[p] * v % P) % P, tag[p] += v;
return;
}
pushdown(p);
int mid = (l + r) >> 1;
if (tl <= mid) modify(ls, l, mid, tl, tr, v);
if (tr > mid) modify(rs, mid + 1, r, tl, tr, v);
sum[p] = (sum[ls] + sum[rs]) % P;
}
int query(int p, int l, int r, int tl, int tr)
{
if (tl <= l && r <= tr) return sum[p];
pushdown(p);
int mid = (l + r) >> 1; LL res = 0;
if (tl <= mid) res = query(ls, l, mid, tl, tr);
if (tr > mid) res += query(rs, mid + 1, r, tl, tr);
return res % P;
}
int main()
{
scanf("%d%d%d", &n, &q, &k);
for(int i = 2; i <= n; i++) scanf("%d", &fa[i]), e[++tot] = edge{h[fa[i]], i}, h[fa[i]] = tot;
dep[1] = 1, dfs1(1), dfs2(1, 1);
for(int i = 1; i <= n; i++) depk[i] = fpow(dep[i], k);
build(1, 1, n);
for(int i = 1, x, y; i <= q; i++) scanf("%d%d", &x, &y), Q[++Tot] = node{H[x], y, i}, H[x] = Tot;
for(int i = 1, x, fx; i <= n; i++)
{
x = i;
for(; x; ) fx = top[x], modify(1, 1, n, dfn[fx], dfn[x], 1), x = fa[fx];
for(int j = H[i]; j; j = Q[j].nxt)
{
x = Q[j].to;
for(; x; ) fx = top[x], ans[Q[j].id] = (ans[Q[j].id] + query(1, 1, n, dfn[fx], dfn[x])) % P, x = fa[fx];
}
}
for(int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
}
标签:rs,int,tag,dep,tl,GZOI2019,GXOI,旧词,ls 来源: https://www.cnblogs.com/leiyuanze/p/15379316.html