1. 程式人生 > >bzoj3626: [LNOI2014]LCA (樹鏈剖分)

bzoj3626: [LNOI2014]LCA (樹鏈剖分)

clas con blog top return print post 節點 std

很神奇的方法

感覺是有生之年都想不到正解的這種

考慮對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; }

bzoj3626: [LNOI2014]LCA (樹鏈剖分)