http://www.lydsy.com/JudgeOnline/problem.php?id=3626
让我比较惊讶的一道链剖裸题(' ' ) 做法很精妙
首先我们考虑对于单个询问时可以拆分成(1, l - 1, z) 和 (1, r, z) 的, 然后考虑对于每一次询问可以表示为将(1, l) 的所有点到根的全部加1 然后求z到根路径的的和。 所以将询问离线, 按询问的l值排序,每一次遇到新的l值就将这一段的点到根的路径全部加1,然后查询即可
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; const ll maxn = 100001; const ll mod = 201314; ll n, m; ll int_get() { ll x = 0; char c = (char)getchar(); bool f = 0; while(!isdigit(c)) { if(c == '-') f = 1; c = (char)getchar(); } while(isdigit(c)) { x = x * 10 + (int)(c - '0'); c = (char)getchar(); } if(f) x = -x; return x; } struct seg { ll data, lazy; seg *l, *r; }tr[maxn * 3];ll sege = 0; seg* root; void test(seg* x, ll l, ll r) { cout << l <<" "<< r <<" "<< x-> data <<" "<< x-> lazy << endl; if(l ^ r) { ll mid = (l + r) >> 1; test(x-> l, l, mid), test(x-> r, mid + 1, r); } } seg* build(ll l, ll r) { seg* x = tr + sege ++; if(l ^ r) { ll mid = (l + r) >> 1; x-> l = build(l, mid); x-> r = build(mid + 1, r); } return x; } void update(seg* x) { if(x-> l) x-> data = x-> l-> data + x-> r-> data; } void pushdown(seg* x, ll l, ll r) { if(x-> l && x-> lazy != 0) { ll mid = (l + r) >> 1; x-> l-> lazy += x-> lazy, x-> l-> data += (mid - l + 1) * x-> lazy; x-> r-> lazy += x-> lazy, x-> r-> data += (r - mid) * x-> lazy; x-> lazy = 0; } } void addlazy(seg* x, ll l, ll r, ll ls, ll rs, ll v) { if(l == ls && r == rs) x-> data += v * (rs - ls + 1), x-> lazy += v; else { pushdown(x, l, r); ll mid = (l + r) >> 1; if(rs <= mid) addlazy(x-> l, l, mid, ls, rs, v); else if(ls > mid) addlazy(x-> r, mid + 1, r, ls, rs, v); else addlazy(x-> l, l, mid, ls, mid, v), addlazy(x-> r, mid + 1, r, mid + 1, rs, v); update(x); } } ll ask(seg* x, ll l, ll r, ll ls, ll rs) { if(l == ls && r == rs) return x-> data; else { pushdown(x, l, r); ll mid = (l + r) >> 1; if(rs <= mid) return ask(x-> l, l, mid, ls, rs); else if(ls > mid) return ask(x-> r, mid + 1, r, ls, rs); else return ask(x-> l, l, mid, ls, mid) + ask(x-> r, mid + 1, r, mid + 1, rs); } } struct edge { ll t; edge* next; }e[maxn * 2], *head[maxn]; ll ne = 0; void addedge(ll f, ll t) { e[ne].t = t, e[ne].next = head[f], head[f] = e + ne ++; } ll h[maxn], size[maxn], fa[maxn], un[maxn], map[maxn], num = 0; void dfs(ll x, ll pre) { fa[x] = pre, size[x] = 1; h[x] = h[pre] + 1; for(edge* p = head[x]; p; p = p-> next) { if(p-> t != pre) dfs(p-> t, x), size[x] += size[p-> t]; } } void divide(ll x, ll Un) { un[x] = Un, map[x] = ++ num; if(size[x] == 1) return ; ll Max = 0, pos; for(edge* p = head[x]; p; p = p-> next) { if(p-> t != fa[x] && size[p-> t] > Max) Max = size[p-> t], pos = p-> t; } divide(pos, Un); for(edge* p = head[x]; p; p = p-> next) { if(p-> t != fa[x] && p-> t != pos) divide(p-> t, p-> t); } } void add(ll a, ll b, ll v) { ll ls, rs; while(un[a] != un[b]) { if(h[un[a]] > h[un[b]]) { ls = map[un[a]], rs = map[a]; addlazy(root, 1, n, ls, rs, v); a = fa[un[a]]; } else { ls = map[un[b]], rs = map[b]; addlazy(root, 1, n, ls, rs, v); b = fa[un[b]]; } } ls = map[a], rs = map[b]; if(ls > rs) swap(ls, rs); addlazy(root, 1, n, ls, rs, v); } ll get(ll a, ll b) { ll ret = 0; ll ls, rs; while(un[a] != un[b]) { if(h[un[a]] > h[un[b]]) { ls = map[un[a]], rs = map[a]; ret += ask(root, 1, n, ls, rs); a = fa[un[a]]; } else { ls = map[un[b]], rs = map[b]; ret += ask(root, 1, n, ls, rs); b = fa[un[b]]; } } ls = map[a], rs = map[b]; if(ls > rs) swap(ls, rs); ret += ask(root, 1, n, ls, rs); return ret; } struct block { ll x, p, pos, fl; }o[maxn]; ll oe = 0; bool cmp(block a, block b) { return a. x < b. x; } ll ans[maxn]; void read() { n = int_get(); m = int_get(); for(ll i = 2; i <= n; ++ i) { ll u = int_get() + 1; addedge(u, i), addedge(i, u); } for(ll i = 1; i <= m; ++ i) { ll a, b, c; a = int_get() + 1, b = int_get() + 1, c = int_get() + 1; ++ oe, o[oe]. x = a - 1, o[oe]. p = c, o[oe]. pos = i, o[oe]. fl = -1; ++ oe, o[oe]. x = b, o[oe]. p = c, o[oe].pos = i, o[oe].fl = 1; } dfs(1, 0), divide(1, 1); root = build(1, n); } void sov() { sort(o + 1, o + 1 + oe, cmp); ll pl = 0; for(ll i = 1; i <= oe; ++ i) { while(pl < o[i]. x) { ++ pl; add(1, pl, 1); } //test(root, 1, n); cout << endl; ans[o[i]. pos] += o[i]. fl * get(1, o[i]. p); } for(ll i = 1; i <= m; ++ i) printf("%lld\n", (ans[i] % mod + mod)% mod); } int main() { //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); read(); sov(); return 0; }