P4211 [LNOI2014] LCA 树链剖分+扫描线

这道题目主要是运用了一个很好的 trick。 \(dep_{LCA(x,y)}\) 可以这样想,将根( \(1\) )到 \(x\) 的路径上的值全部加一,然后求 \(1\)\(y\) 路径上的值。那么这道题目就被转化为了一个类似扫描线的问题。

这个 trick 为这题 90% 的难度。因此开一个 trick 合集吧。

#include <bits/stdc++.h>
#define debug puts("Wait for me.");
template <typename T>void read(T& t){t=0; char ch=getchar(); int fflag=1;while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;}
template <typename T,typename... Args>void read(T& t, Args&... args){read(t);read(args...);}
template <typename T>void write(const T &x) {if(x < 10) {putchar(x + '0');return;}write(x / 10);putchar(x % 10 + '0');}
#define pb push_back
using namespace std;
#define rep(I,J,K) for(int I=(int)J;I<=(int)K;++I)
#define per(I,J,K) for(int I=(int)J;I>=(int)K;--I)
typedef long long ll;typedef double db;typedef pair<int,int>pii;
mt19937 mrand(random_device{}());
int rnd(int x){return mrand()%x;}
// head

const int N = 5e4 + 10,inf = 0x3f3f3f3f, P = 201314;

int n, m, dfn[N], zr[N], sz[N], top[N], _dfn[N];
vector<int>G[N];

struct Ques {
    int x, z, id, fh;
    bool operator < (const Ques &ques) const {
        return x < ques.x;
    }
}Q[N << 1];
int cnt = 0, tot = 0, ans[N], fa[N];
void add(int &x, int y) {x += y; if(x >= P) x -= P;}
void del(int &x, int y) {x -= y; if(x < 0) x += P;}

struct Fenwick_Tree {
    int val1[N], val2[N];
    int lowbit(int x) {return x & (-x);}
    void modify(int x, int va,int val[]) {
        while(x <= n) {
            if(va > 0) add(val[x], va);
            if(va < 0) del(val[x], -va);
            x += lowbit(x);
        }
    }
    void modify(int l, int r, int va) {
        // 给区间 l 到 r 加上 va
        modify(l, va, val1); modify(r + 1, -va, val1);
        modify(l, va * l % P, val2); modify(r + 1, -((r + 1) * va % P), val2);
    }
    int query(int x, int val[]) {
        if(x == -1) return 0;
        int res = 0;
        while(x) {
            add(res, val[x]);
            // cout << x << endl;
            x -= lowbit(x);
        }
        return res;
    }
    int Query(int x) {
        return ((ll)(x + 1) * query(x, val1) % P - query(x, val2) + P) % P;
    }
    int Query(int l, int r) {
        return (Query(r) - Query(l - 1) + P) % P;
    }
}bit;

void dfs(int u) {
    sz[u] = 1;
    for(int v : G[u]) {
        dfs(v);
        sz[u] += sz[v];
        if(sz[v] > sz[zr[u]]) zr[u] = v;
    }
}
void dfs2(int u, int tp) {
    top[u] = tp; _dfn[dfn[u] = ++cnt] = u;
    if(zr[u]) dfs2(zr[u], tp);
    for(int v : G[u]) if(v != zr[u]) dfs2(v, v);
}
int Query(int x) {
    // 查询 1-x 路径上的权值和
    if(x == 0) return 0;
    int res = 0;
    while(top[x] != 1) {
        // cout << x << endl;
        add(res, bit.Query(dfn[top[x]], dfn[x]));
        x = fa[top[x]];
    }
    add(res, bit.Query(dfn[top[x]], dfn[x]));
    return res;
}
void modify(int x) {
    // 1-x 路径上权值全部加一
    while(top[x] != 1) bit.modify(dfn[top[x]], dfn[x], 1), x = fa[top[x]];
    bit.modify(dfn[top[x]], dfn[x], 1);
    return;
}

int main(){
    read(n, m);
    rep(i, 2, n) {
        read(fa[i]);
        ++fa[i];
        G[fa[i]].pb(i);
    }
    dfs(1);
    dfs2(1, 1);
    rep(i, 1, m) {
        int l, r, z;
        read(l, r, z);
        ++l, ++r; ++z;
        Q[++tot] = {l - 1, z, i, -1};
        Q[++tot] = {r, z, i, 1};
    }
    sort(Q + 1, Q + tot + 1);
    int cur = 1;
    rep(i, 0, n) {
        if(i) modify(i);
        while(cur <= tot && Q[cur].x <= i) {
            if(Q[cur].fh == 1) add(ans[Q[cur].id], Query(Q[cur].z));
            else del(ans[Q[cur].id], Query(Q[cur].z));
            ++cur;
        }
    }
    rep(i, 1, m) cout << ans[i] << endl;
    return 0;
}
posted @ 2026-08-22 19:03  Mercury_City  阅读(8)  评论(0)    收藏  举报