【GZOI2019】旧词

题目链接:https://www.luogu.com.cn/problem/P5305

题目大意:给定一棵有根树,已知常数 \(k\), 对于 \(Q\) 个询问 \(x, y\)\(\sum\limits_{i \leq x} {depth(Lca(i, z))^k}\)

solution

\(k = 1\) 时, 显然就是原题【LN2014】LCA

\(k \ne 1\) , 则可以进一步推广上一题的算法 , 对于每次修改点到根的权值分别加 1 其实就是对 \(depth\)的一种差分\((depth(i) - depth(father(i)) = 1)\)

现在依然可以将 \(depth^k\) 进行差分, 则若点 \(i\) 的深度为\(dep_i\) , 则 \(i\) 的权值每次应该增加\({dep_i}^k - (dep_i - 1)^k\) , 最后从根节点到点的路径上的和即为 \({dep_i}^k\) , 可以先处理差分权值在dfs序区间上的前缀和 , 然后用树剖 + 线段树 , 离线进行修改与维护

时间复杂度: \(O(nlog^2n)\)

code

#include<bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &FF) {
    int RR = 1; FF = 0; char CH = getchar();
    for(; !isdigit(CH); CH = getchar()) if(CH == '-') RR = -RR;
    for(; isdigit(CH); CH = getchar()) FF = FF * 10 + CH - 48;
    FF *= RR;
}
inline void file(string str) {
    freopen((str + ".in").c_str(), "r", stdin);
    freopen((str + ".out").c_str(), "w", stdout);
}
#define mod 998244353
#define int long long
const int N = 1e5 + 10;
int now, fst[N], nxt[N], num[N], dep[N], n, q, k, sum[N];
int p = 1, si, fa[N], tp[N], rev[N], sg[N], size[N], son[N], ans[N];
void add(int u, int v) {
    nxt[++now] = fst[u], fst[u] = now, num[now] = v;
    nxt[++now] = fst[v], fst[v] = now, num[now] = u;
}
struct Segment_tree{
    int val, tag;
}xds[N << 2];
struct Que{
    int id, pi, qi;
    friend bool operator < (Que ai, Que bi) {
        return ai.pi < bi.pi;
    }
}qi[N];
void push_up(int pos) {
    xds[pos].val = (xds[pos << 1].val + xds[pos << 1 | 1].val) % mod;
}
void Add(int pos, int l, int r, int k) {
    xds[pos].val = (xds[pos].val + k * ((sum[r] - sum[l - 1] + mod) % mod) % mod) % mod;
    xds[pos].tag = (xds[pos].tag + k) % mod;
}
void push_down(int pos, int l, int r) {
    if(xds[pos].tag == 0) return;
    int mid = (l + r) >> 1;
    Add(pos << 1, l, mid, xds[pos].tag);
    Add(pos << 1 | 1, mid + 1, r, xds[pos].tag);
    xds[pos].tag = 0;
}
void modify(int pos, int l, int r, int ll, int rr) {
    if(l >= ll && r <= rr) {
        Add(pos, l, r, 1);
        return;
    }
    push_down(pos, l, r);
    int mid = (l + r) >> 1;
    if(mid >= ll) modify(pos << 1, l, mid, ll, rr);
    if(mid < rr) modify(pos << 1 | 1, mid + 1, r, ll, rr);
    push_up(pos);
}
int query(int pos, int l, int r, int ll, int rr) {
    if(l >= ll && r <= rr) return xds[pos].val;
    push_down(pos, l, r);
    int mid = (l + r) >> 1, res = 0;
    if(mid >= ll) res = (res + query(pos << 1, l, mid, ll, rr)) % mod;
    if(mid < rr) res = (res + query(pos << 1 | 1, mid + 1, r, ll, rr)) % mod;
    return res;
}
void fst_dfs(int xi) {
    size[xi] = 1, dep[xi] = dep[fa[xi]] + 1;
    for(int i = fst[xi]; i; i = nxt[i])
        if(num[i] != fa[xi]) {
            fst_dfs(num[i]);
            size[xi] += size[num[i]];
            if(size[num[i]] > size[son[xi]])
                son[xi] = num[i];
        }
}
void nxt_dfs(int xi) {
    if(son[xi]) {
        sg[++si] = son[xi], rev[son[xi]] = si;
        tp[son[xi]] = tp[xi], nxt_dfs(son[xi]);
    }
    for(int i = fst[xi]; i; i = nxt[i])
        if(num[i] != son[xi] && num[i] != fa[xi]) {
            sg[++si] = num[i], rev[num[i]] = si;
            tp[num[i]] = num[i], nxt_dfs(num[i]);
        }
}
int Qpow(int ai, int ki) {
    if(ki <= 1) return ki ? ai % mod : 1;
    int hi = Qpow(ai, ki / 2); hi = hi * hi % mod;
    return ki & 1 ? hi * ai % mod : hi;
}
void modify_list(int xi) {
    while(xi) {
        modify(1, 1, n, rev[tp[xi]], rev[xi]);
        xi = fa[tp[xi]];
    }
}
int query_list(int xi) {
    int res = 0;
    while(xi) {
        res = (res + query(1, 1, n, rev[tp[xi]], rev[xi])) % mod;
        xi = fa[tp[xi]];
    }
    return res;
}
signed main() {
    //file(""); 
    read(n), read(q), read(k);
    for(int i = 2; i <= n; i++)
        read(fa[i]), add(fa[i], i);
    si = tp[1] = rev[1] = sg[1] = 1;
    fst_dfs(1), nxt_dfs(1);
    for(int i = 1; i <= n; i++)
        sum[i] = ((sum[i - 1] + Qpow(dep[sg[i]], k)) % mod - Qpow(dep[sg[i]] - 1, k) + mod) % mod;
    for(int i = 1; i <= q; i++)
        read(qi[i].pi), read(qi[i].qi), qi[i].id = i;
    sort(qi + 1, qi + q + 1);
    //cout << query(1, 1, n, rev[2], rev[2]) << endl;
    for(int i = 1; i <= n; i++) {
        modify_list(i);
        //cout << query(1, 1, n, rev[3], rev[3]) << endl;
        while(qi[p].pi == i)
            ans[qi[p].id] = query_list(qi[p].qi), p++;
    }
    for(int i = 1; i <= q; i++) cout << ans[i] << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/magicduck/p/12238897.html