bzoj3626: [LNOI2014]LCA (树链剖分)

 很神奇的方法

 感觉是有生之年都想不到正解的这种

 考虑对i 到根的节点权值 + 1,则从根到z的路径和就是lca(i,z)的深度

 所以依次把0 ~ n - 1的点权值 + 1

 对于询问[l, r] 这个区间关于z 的深度和,就用(1, r) - (1, l - 1)的值表示

 详见黄学长的博客啦

 http://hzwer.com/3415.html

 下面给出代码

 

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 50000 + 10;
const int MOD = 201314;
  
struct Query {
    int u, id, z, flag;
    inline bool operator < (const Query &o) const {
        return u < o.u;
    }
} Q[N * 2];
int n, q, tot, cnt;
int sz[N], dep[N], fa[N], hs[N], top[N], pos[N];
vector < int > E[N];
  
#define isdigit(x) (x >= '0' && x <= '9')
inline void read(int &ans) {
    ans = 0;
    static char buf = getchar();
    for (; !isdigit(buf); buf = getchar());
    for (; isdigit(buf); buf = getchar())
        ans = ans * 10 + buf - '0';
}
  
void dfs1(int x, int d, int f) {
    dep[x] = d; fa[x] = f;
    sz[x] = 1;  hs[x] = -1;
    int tmp = 0;
    for (int i = 0; i < E[x].size(); i++) {
        int u = E[x][i];
        dfs1(u, d + 1, x);
        if (sz[u] > tmp)
            hs[x] = u, tmp = sz[u];
        sz[x] += sz[u];
    }
}
  
void dfs2(int x, int t) {
    top[x] = t; pos[x] = ++tot;
    if (hs[x] == -1)    return ;
    dfs2(hs[x], t);
    for (int i = 0; i < E[x].size(); i++)
        if (E[x][i] != hs[x])
            dfs2(E[x][i], E[x][i]);
}
  
int add[N * 3], sum[N * 3];
#define g(l, r) (l + r | l != r) 
#define o g(l, r)
#define ls g(l, mid)
#define rs g(mid + 1, r)
  
inline void pushDown(int l, int r) {
    if (!add[o] || l == r)  return ;
    int mid = l + r >> 1;
    add[ls] += add[o]; 
    sum[ls] += add[o] * (mid - l + 1);
    add[rs] += add[o];
    sum[rs] += add[o] * (r - mid);
    add[o] = 0;
}
  
inline void pushUp(int l, int r) {
    int mid = l + r >> 1;
    sum[o] = sum[ls] + sum[rs];
}
  
void modify(int l, int r, int L, int R) {
    if (l >= L && r <= R) {
        sum[o] += r - l + 1;
        add[o]++;
        return ;
    }
    pushDown(l, r);
    int mid = l + r >> 1;
    if (L <= mid)    modify(l, mid, L, R);
    if (R > mid) modify(mid + 1, r, L, R);
    pushUp(l, r);
}
  
inline void modify(int x, int y) {
    int f1 = top[x], f2 = top[y];
    while (f1 != f2) {
        if (dep[f1] < dep[f2])
            swap(x, y), swap(f1, f2);
        modify(1, n, pos[f1], pos[x]);
        x = fa[f1]; f1 = top[x];
    }
    if (dep[x] > dep[y]) swap(x, y);
    modify(1, n, pos[x], pos[y]);
}
  
int query(int l, int r, int L, int R) {
    if (l >= L && r <= R) return sum[o];
    pushDown(l, r);
    int mid = l + r >> 1;
    int ans = 0;
    if (L <= mid)    ans += query(l, mid, L, R);
    if (R > mid) ans += query(mid + 1, r, L, R);
    return ans;
}
  
inline int query(int x, int y) {
    int f1 = top[x], f2 = top[y];
    int ans = 0;
    while (f1 != f2) {
        if (dep[f1] < dep[f2])
            swap(x, y), swap(f1, f2);
        ans = (ans + query(1, n, pos[f1], pos[x])) % MOD;
        x = fa[f1]; f1 = top[x];
    }
    if (dep[x] > dep[y]) swap(x, y);
    ans = (ans + query(1, n, pos[x], pos[y])) % MOD;
    return ans;
}
  
int ans1[N], ans2[N];
int main() {
    read(n); read(q);
    for (int i = 1; i < n; i++) {
        int x; read(x); 
        E[x].push_back(i);
    }
    dfs1(0, 1, -1); dfs2(0, 0);
    for (int i = 1; i <= q; i++) {
        int l, r, z;
        read(l); read(r); read(z);  
        Q[++cnt] = (Query) {l - 1, i, z, 0};
        Q[++cnt] = (Query) {r, i, z, 1};
    }
    sort(Q + 1, Q + cnt + 1);
    int now = -1;
    for (int i = 1; i <= cnt; i++) {
        while (now < Q[i].u) ++now, modify(now, 0);
        if (!Q[i].flag)  ans1[Q[i].id] = query(Q[i].z, 0);
        else    ans2[Q[i].id] = query(Q[i].z, 0);
    }
    for (int i = 1; i <= q; i++)
        printf("%d\n", (ans2[i] - ans1[i] + MOD) % MOD);
    return 0;
}

 

posted @ 2018-03-18 23:10  cminus  阅读(166)  评论(0编辑  收藏  举报