[BZOJ3626]LCA

題目鏈接BZOJ3626

題目大意
給出一棵樹,若干個詢問:lrx ,求ri=ldep[LCA(i,x)]

分析
比較巧妙的一道題。
1. 首先定義一個操作cover(i) ,表示使iroot 的路徑上所有點權+1,這個操作用樹剖處理;定義dist[i]iroot 路徑上的點權和。
2. 考慮兩個點ij ,初始化點權均爲0,若cover(i) ,那麼dist[j] 即爲dep[LCA(i,j)] ;而且這個操作是可以疊加的:對於lr 的每個點,都進行一次cover 操作,那麼dist[x] 即爲ri=ldep[LCA(i,x)]
3. 而且可以用前綴和的形式離線求解:依次對每個點進行cover 操作,若有一個詢問lrx ,則在cover(l1) 時記錄D1=dist[x] ,在cover(r) 時記錄D2=dist[x] ,那麼D2D1 即爲答案。

上代碼

#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 5e4 + 10;
const int MOD = 201314;

int n, m;
inline int read() {
    char ch;
    int ans = 0, neg = 1;
    while (!isdigit(ch = getchar()))
        if (ch == '-') neg = -1;
    while (isdigit(ch))
        ans = ans * 10 + ch - '0', ch = getchar();
    return ans * neg;
}

vector <int> edge[N];

int fa[N], son[N], dep[N], size[N];
int top[N], plc[N], replc[N], cntSeg;
void dfs1(int a, int par) {
    fa[a] = par, dep[a] = dep[par] + 1, size[a] = 1;
    for (int i = 0; i < edge[a].size(); i++) {
        int now = edge[a][i];
        if (now == par) continue;
        dfs1(now, a), size[a] += size[now];
        if (size[now] > size[son[a]]) son[a] = now;
    }
}
void dfs2(int a, int up) {
    top[a] = up, plc[a] = ++cntSeg, replc[cntSeg] = a;
    if (son[a]) dfs2(son[a], up);
    for (int i = 0; i < edge[a].size(); i++) {
        int now = edge[a][i];
        if (now == fa[a] || now == son[a]) continue;
        dfs2(now, now);
    }
}

int add[N * 3], tot[N * 3];
#define lc(a) ((a) << 1)
#define rc(a) (lc(a) | 1)
#define Len(l, r) ((r) - (l) + 1)
inline void pushUp(int a) {
    tot[a] = tot[lc(a)] + tot[rc(a)];
}
inline void pushDown(int a, int l, int r) {
    int mid = (l + r) >> 1;
    add[lc(a)] += add[a], add[rc(a)] += add[a];
    tot[lc(a)] = (tot[lc(a)] + add[a] * Len(l, mid)) % MOD;
    tot[rc(a)] = (tot[rc(a)] + add[a] * Len(mid + 1, r)) % MOD;
    add[a] = 0;
}
void modify(int a, int l, int r, int ll, int rr) {
    if (l == ll && r == rr) {
        add[a] = (add[a] + 1 == MOD ? 0 : add[a] + 1);
        return tot[a] = (tot[a] + Len(l, r)) % MOD, void(0);
    }
    pushDown(a, l, r);
    int mid = (l + r) >> 1;
    if (rr <= mid) modify(lc(a), l, mid, ll, rr);
    else if (ll > mid) modify(rc(a), mid + 1, r, ll, rr);
    else modify(lc(a), l, mid, ll, mid), modify(rc(a), mid + 1, r, mid + 1, rr);
    pushUp(a);
}
int query(int a, int l, int r, int ll, int rr) {
    if (l == ll && r == rr) return tot[a];
    pushDown(a, l, r);
    int mid = (l + r) >> 1;
    if (rr <= mid) return query(lc(a), l, mid, ll, rr);
    else if (ll > mid) return query(rc(a), mid + 1, r, ll, rr);
    return query(lc(a), l, mid, ll, mid) + query(rc(a), mid + 1, r, mid + 1, rr);
}
inline void decomMdf(int a, int b) {
    while (top[a] != top[b]) {
        if (dep[top[a]] < dep[top[b]]) swap(a, b);
        modify(1, 1, n, plc[top[a]], plc[a]);
        a = fa[top[a]];
    }
    if (dep[a] < dep[b]) swap(a, b);
    return modify(1, 1, n, plc[b], plc[a]);
}
inline int decomTot(int a, int b) {
    int ans = 0;
    while (top[a] != top[b]) {
        if (dep[top[a]] < dep[top[b]]) swap(a, b);
        ans += query(1, 1, n, plc[top[a]], plc[a]);
        a = fa[top[a]];
    }
    if (dep[a] < dep[b]) swap(a, b);
    return ans + query(1, 1, n, plc[b], plc[a]);
}

struct Ask {
    int poi, *plc;
    Ask(int _poi = 0, int *_plc = 0): poi(_poi), plc(_plc) {}
}; vector <Ask> ask[N];
struct Ans {
    int plus, minus;
    inline void output() {
        plus = (plus - minus) % MOD;
        printf("%d\n", plus < 0 ? plus + MOD : plus);
    }
} ans[N];
void init() {
    n = read(), m = read();
    for (int i = 2; i <= n; i++) {
        int a = read() + 1;
        edge[i].push_back(a), edge[a].push_back(i);
    }
    dfs1(1, 0), dfs2(1, 1);
    for (int i = 1; i <= m; i++) {
        int l = read() + 1, r = read() + 1, a = read() + 1;
        ask[r].push_back(Ask(a, &ans[i].plus));
        ask[l - 1].push_back(Ask(a, &ans[i].minus));
    }
}
void figure() {
    for (int i = 1; i <= n; i++) {
        decomMdf(1, i);
        for (int j = 0; j < ask[i].size(); j++) {
            int tmp = ask[i][j].poi;
            *ask[i][j].plc = decomTot(1, tmp);
        }
    }
    for (int i = 1; i <= m; i++) ans[i].output();
}

int main() {
    init();
    figure();
    return 0;
}

以上

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章