[LNOI2014]LCA

Problem

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 ;
}
posted @ 2019-11-06 12:19  _Isaunoya  阅读(173)  评论(0编辑  收藏  举报