P4211 [LNOI2014]LCA 题解
求 \(dep_{LCA(u, v)}\) 可以转换成将从根到 \(u\) 的路径 \(+ 1\),然后求从根到 \(v\) 的路径和。
求 \(\sum_{i=l}^r dep_{LCA(i, z)}\) 可以转换成求每个点 \(i\) 到根 $ +1$,然后求路径和。
发现可以用前缀和, 因为 \([1, u_1]\) 和 \([1, u_1+1]\) 之间有很多的重复部分。
考虑离线下来,按照 \(u\) 排序去操作,复杂度 \(\mathcal{O}(n \log^2 n)\)。
/**
* author: TLE_Automation
* creater: 2022.9.7
**/
#include<cmath>
#include<queue>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int mod = 201314;
const ll inf = 0x3f3f3f3f3f3f3f3f;
#define debug cout << "i ak ioi" << "\n"
inline void print(int x) {if (x < 0) putchar('-'), x = -x; if(x > 9) print(x / 10); putchar(x % 10 + '0');}
inline char readchar() {static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;}
inline int read() { int res = 0, f = 0; char ch = gc();for (; !isdigit(ch); ch = gc()) f |= (ch == '-'); for (; isdigit(ch); ch = gc()) res = (res << 1) + (res << 3) + (ch ^ '0'); return f ? -res : res;}
int n, m, cnt = 0;
vector <int> E[N];
struct Question {
int num, pos, z, flg;
bool operator < (const Question &x) const { return pos < x.pos;}
}q[N];
struct Ans { int ansl, ansr, num;} ans[N];
int idx, dfn[N], top[N], son[N], siz[N], dep[N], fa[N], rk[N];
namespace Seg {
#define lson rt << 1
#define rson rt << 1 | 1
struct Node {int l, r, lazy, sum; } tree[N << 2];
void build(int rt, int l, int r) {
tree[rt].l = l, tree[rt].r = r;
if(l == r) return;
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
}
void pushdown(int rt) {
tree[lson].lazy += tree[rt].lazy, tree[rson].lazy += tree[rt].lazy;
tree[lson].sum += (tree[lson].r - tree[lson].l + 1) * tree[rt].lazy;
tree[rson].sum += (tree[rson].r - tree[rson].l + 1) * tree[rt].lazy;
tree[lson].lazy %= mod, tree[rson].lazy %= mod, tree[lson].sum %= mod, tree[rson].sum %= mod;
tree[rt].lazy = 0;
}
void add(int rt, int l, int r, int k) {
if(tree[rt].l > r || tree[rt].r < l) return;
if(tree[rt].l >= l && tree[rt].r <= r) {
tree[rt].sum += (tree[rt].r - tree[rt].l + 1) * k;
tree[rt].lazy += k; return;
} pushdown(rt);
add(lson, l, r, k), add(rson, l, r, k);
tree[rt].sum = (tree[lson].sum + tree[rson].sum) % mod;
}
int query(int rt, int l, int r) {
if(tree[rt].l > r || tree[rt].r < l) return 0;
if(tree[rt].l >= l && tree[rt].r <= r) return tree[rt].sum;
pushdown(rt); return (query(lson, l, r) + query(rson, l, r)) % mod;
}
}
using namespace Seg;
namespace Cut {
void dfs1(int u, int Fa) {
siz[u] = 1, dep[u] = dep[Fa] + 1, fa[u] = Fa;
for(int v : E[u]) {
if(v == Fa) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs2(int u, int tp) {
top[u] = tp, dfn[u] = ++idx, rk[idx] = u;
if(son[u]) dfs2(son[u], tp);
for(int v : E[u]) {
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
void change(int x, int y) {
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
add(1, dfn[top[x]], dfn[x], 1);
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
add(1, dfn[y], dfn[x], 1);
}
int Query(int x, int y) {
int ans = 0;
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ans = (ans + query(1, dfn[top[x]], dfn[x])) % mod;
x = fa[top[x]];
}
if(dep[x] < dep[y]) swap(x, y);
ans = (ans + query(1, dfn[y], dfn[x])) % mod;
return ans;
}
}
using namespace Cut;
signed main()
{
n = read(), m = read();
for(int i = 2; i <= n; i++) {
int x = read() + 1; E[x].push_back(i);
}
for(int i = 1; i <= m; i++) {
int l = read() + 1, r = read() + 1, z = read() + 1;
q[++cnt] = (Question) {i, r, z, 1};
q[++cnt] = (Question) {i, l - 1, z, 0};
}
dfs1(1, 0), dfs2(1, 0), build(1, 1, n);
sort(q + 1, q + cnt + 1);
int now = 0;
for(int i = 1; i <= cnt; i++) {
while(now < q[i].pos) change(1, ++now);
if(q[i].flg) ans[q[i].num].ansr = Query(1, q[i].z);
else ans[q[i].num].ansl = Query(1, q[i].z);
}
for(int i = 1; i <= m; i++) printf("%d\n", (ans[i].ansr - ans[i].ansl + mod) % mod);
return (0 - 0);
}

离线树剖好题
浙公网安备 33010602011771号