q个询问
给出\(l,r,z\)
求 \(\sum_{i=l}^{r} dep[Lca(i,z)]\)
\(n,q \leq 5*10^4\)
这显然是不太可做的 如果你要用 \(nq \log n\) 的做法
考虑离线。
把俩询问拆成 [\(1,l-1\)] , [\(1,r\)]
求出来的结果自然是 [\(1,r\)] - [\(1,l-1\)]
没有固定的点?怎么办?
我们想。假设当前询问点是 z 选到 x 这个点 (\(l \leq x \leq r\))
那么 z 和 x 的 LCA 一定在 x 和 1 的路径上
所以每次 链上修改 把 x -> 1 的这条链整体加1
查询的时候 查询 1 ~ z 的链上的值就可以了。
至于链上整体加1 以及链上查询 可以用树链剖分+线段树解决。
如果没能理解 很抱歉我菜的可怜只能放一张比较特殊的图 让读者自行理解了。。
#include<bits/stdc++.h> using namespace std ; const int MAXN = 5e4 + 10 ; struct Query { int z , flg , id ; } ; vector < Query > v[MAXN] ; int n , Q ; struct Edge { int v , nxt ; } e[MAXN << 1] ; int head[MAXN] , cnt = 0 ; inline void add(int u , int v) { e[++ cnt] = {v , head[u]} ; head[u] = cnt ; } typedef int arr[MAXN] ; arr sz , fa , d , son ; inline void dfs(int u) { sz[u] = 1 ; for(register int i = head[u] ; i ; i = e[i].nxt) { int v = e[i].v ; if(v == fa[u]) continue ; fa[v] = u ; d[v] = d[u] + 1 ; dfs(v) ; sz[u] += sz[v] ; if(sz[v] > sz[son[u]]) son[u] = v ; } } arr top , id , seq ; int idx = 0 ; inline void dfs(int u , int t) { top[u] = t ; id[u] = ++ idx ; seq[idx] = u ; if(! son[u]) return ; dfs(son[u] , t) ; for(register int i = head[u] ; i ; i = e[i].nxt) { int v = e[i].v ; if(v == fa[u] || v == son[u]) continue ; dfs(v , v) ; } } const int Mod = 201314 ; int sum[MAXN << 2] , tag[MAXN << 2] ; inline void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1] ; if(sum[rt] >= Mod) sum[rt] -= Mod ; } inline void build(int l , int r , int rt) { if(l == r) { sum[rt] = tag[rt] = 0 ; return ; } int mid = l + r >> 1 ; build(l , mid , rt << 1) ; build(mid + 1 , r , rt << 1 | 1) ; pushup(rt) ; } inline void pushdown(int rt , int l , int r) { if(! tag[rt]) return ; tag[rt << 1] += tag[rt] ; tag[rt << 1 | 1] += tag[rt] ; int mid = l + r >> 1 ; sum[rt << 1] += tag[rt] * (mid - l + 1) ; sum[rt << 1 | 1] += tag[rt] * (r - mid) ; tag[rt] = 0 ; return ; } inline void update(int a , int b , int l , int r , int rt) { if(a <= l && r <= b) { sum[rt] += r - l + 1 ; tag[rt] ++ ; return ; } pushdown(rt , l , r) ; int mid = l + r >> 1 ; if(a <= mid) update(a , b , l , mid , rt << 1) ; if(b > mid) update(a , b , mid + 1 , r , rt << 1 | 1) ; pushup(rt) ; } inline int query(int a , int b , int l , int r , int rt) { if(a <= l && r <= b) { return sum[rt] ; } pushdown(rt , l , r) ; int mid = l + r >> 1 , ans = 0 ; if(a <= mid) ans += query(a , b , l , mid , rt << 1) ; if(b > mid) ans += query(a , b , mid + 1 , r , rt << 1 | 1) ; return ans ; } inline void upd_range(int x , int y) { int fx = top[x] , fy = top[y] ; while(fx ^ fy) { if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ; update(id[fx] , id[x] , 1 , n , 1) ; x = fa[fx] , fx = top[x] ; } if(d[x] > d[y]) swap(x , y) ; update(id[x] , id[y] , 1 , n , 1) ; } inline int query_range(int x , int y) { int fx = top[x] , fy = top[y] , ans = 0 ; while(fx ^ fy) { if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ; ans += query(id[fx] , id[x] , 1 , n , 1) ; x = fa[fx] , fx = top[x] ; } if(d[x] > d[y]) swap(x , y) ; return ans += query(id[x] , id[y] , 1 , n , 1) ; } int ans[MAXN] ; signed main() { #define _WIN64 freopen("0.in" , "r" , stdin) ; #endif ios_base :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ; cin >> n >> Q ; for(int i = 2 ; i <= n ; i ++) { int fa ; cin >> fa ; add(i , ++ fa) ; add(fa , i) ; } dfs(1) ; dfs(1 , 1) ; build(1 , n , 1) ; for(int i = 1 ; i <= Q ; i ++) { int l , r , z ; cin >> l >> r >> z ; ++ l ; ++ r ; ++ z ; v[l - 1].push_back({z , - 1 , i}) ; v[r].push_back({z , 1 , i}) ; } for(register int i = 1 ; i <= n ; i ++) { upd_range(1 , i) ; for( Query x : v[i] ) ans[x.id] = (ans[x.id] + x.flg * query_range(1 , x.z) + Mod) % Mod ; } for(register int i = 1 ; i <= Q ; i ++) cout << ans[i] << '\n' ; return 0 ; }
来源:博客园
作者:_Isaunoya
链接:https://www.cnblogs.com/Isaunoya/p/11804422.html