Loading

P4211 [LNOI2014]LCA

题面

一棵 \(n\) 个节点的有根树,\(m\) 次询问,每次给出 \(l,r,z\)

\(\sum_{i = l}^rdep[LCA(i,z)]\)

\(n\leq50000,1\leq m\leq 50000\)

solution

超级神奇的转化

该询问可以转化为把 \(l-r\) 区间内的所有点各自到根节点的所有权值都 +1,最后求出 \(z\) 到根节点的权值和就是答案

树上区间加肯定是树剖解决,如果每次询问都循环每个点进行区间加,然后清空,时间复杂度 \(O(mnlog^2n)\) 那么就和暴力没什么区别了

考虑怎么优化掉 m 这个复杂度

考虑离线,差分

把所有的询问都按照左端点从小到大排序,然后对每个点扫一遍,同时进行树上区间加,每个区间的答案差分得到就好了

code

/*
work by: Ariel
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#define int long long 
using namespace std;
const int mod = 201314;
const int MAXN = 5e5 + 5;
int read() {
   int x = 0, f = 1; char c = getchar();
   while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
   while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}
   return x * f;
}
int n, m;
struct edge{int v, nxt;}e[MAXN << 1];
int E, head[MAXN];
void add_edge(int u, int v) {
   e[++E] = (edge) {v, head[u]};
   head[u] = E;
}
struct Question{
   int id, pos, z, flg;
   bool operator < (const Question &x) const{
         return pos < x.pos; 
   }
}q[MAXN];
namespace Seg{
   #define lson rt << 1
   #define rson rt << 1|1
   struct Tree{int len, sum, lzy;}tree[MAXN << 2];
   void push_up(int rt) {
   	 tree[rt].sum = (tree[lson].sum + tree[rson].sum) % mod;
   }
   void build(int rt, int l, int r) {
   	   tree[rt].len = r - l + 1;
   	   if (l == r){
   	     tree[rt].sum = tree[rt].lzy = 0;
	     return;	
	   }
	   int mid = (l + r) >> 1;
	   build(lson, l, mid), build(rson, mid + 1, r);
	   push_up(rt);
   }
   void push_down(int rt) {
   	  if (!tree[rt].lzy) return;
   	  tree[lson].lzy += tree[rt].lzy, tree[rson].lzy += tree[rt].lzy;
   	  tree[lson].sum = (tree[lson].sum + tree[lson].len * tree[rt].lzy) % mod;
   	  tree[rson].sum = (tree[rson].sum + tree[rson].len * tree[rt].lzy) % mod;
   	  tree[rt].lzy = 0;
   }
   void update(int rt, int l, int r, int L, int R) {
   	   if (l > R || r < L) return ;
   	   if (L <= l && r <= R) {
   	   	   tree[rt].lzy += 1ll;
   	   	   tree[rt].sum += tree[rt].len;
   	   	   return ;
		}
	   push_down(rt);
	   int mid = (l + r) >> 1;
	   if (L <= mid) update(lson, l, mid, L, R);
	   if (R > mid) update(rson, mid + 1, r, L, R);
	   push_up(rt);
   }
   int query(int rt, int l, int r, int L, int R) {
   	   if (l > R || r < L) return 0;
   	   if (L <= l && r <= R) return tree[rt].sum;
   	   push_down(rt);
   	   int mid = (l + r) >> 1, ret = 0;
   	   if (L <= mid) ret += query(lson, l, mid, L, R);
   	   if (R > mid) ret += query(rson, mid + 1, r, L, R);
   	   return ret;
   }
}

using namespace Seg;

int dep[MAXN], siz[MAXN], son[MAXN], top[MAXN], fa[MAXN], id[MAXN], o;
namespace Cut{
   void dfs(int x, int f) {
   	  dep[x] = dep[f] + 1, fa[x] = f, siz[x] = 1;
   	  for (int i = head[x]; i; i = e[i].nxt) {
   	  	    int v = e[i].v;
			if (v == f) continue;
			dfs(v, x);
			siz[x] += siz[v];
			if (siz[v] > siz[son[x]]) son[x] = v;  
		}
   }
   void dfs2(int x, int tp) {	
   	  top[x] = tp, id[x] = ++o;
   	  if (son[x]) dfs2(son[x], tp);
   	  for (int i = head[x]; i; i = e[i].nxt) {
   	        int v = e[i].v;
			if (v == fa[x] || v == son[x]) continue;
			dfs2(v, v);	  
	   }
   }
   void Modify(int x, int y) {
   	   while(top[x] != top[y]) {
   	   	   if (dep[top[x]] < dep[top[y]]) swap(x, y);
   	   	   update(1, 1, n, id[top[x]], id[x]);
   	   	   x = fa[top[x]];
		}
	   if (dep[x] > dep[y]) swap(x, y);
	   update(1, 1, n, id[x], id[y]);
   }
   int Query(int x, int y) {
   	   int ret = 0;
   	   while(top[x] != top[y]) {
   	   	  if (dep[top[x]] < dep[top[y]]) swap(x, y);
   	   	  ret = (ret + query(1, 1, n, id[top[x]], id[x])) % mod;
   	   	  x = fa[top[x]];
	   }
	   if (dep[x] > dep[y]) swap(x, y);
	   ret = (ret + query(1, 1, n, id[x], id[y]));
	   return ret;
   }
}

using namespace Cut;
int cnt, Ans[MAXN];
signed main() {
   n = read(), m = read();
   for (int i = 2, u; i <= n; i++) {
   	  u = read() + 1;
   	  add_edge(i, u), add_edge(u, i);
   }
   build(1, 1, n);
   dfs(1, 0);
   dfs2(1, 0);
   for (int i = 1, l, r, z; i <= m; i++) {
   	 l = read() + 1, r = read() + 1, z = read() + 1;
   	 q[++cnt] = (Question) {i, l - 1, z, 0};
   	 q[++cnt] = (Question) {i, r, z, 1};
   }
   sort(q + 1, q + cnt + 1);
   int cur = 1;
   for (int i = 1; i <= cnt; i++) {
   	  while(cur <= q[i].pos) Modify(1, cur++);
   	  if (q[i].flg == 0) Ans[q[i].id] -= Query(1, q[i].z);
	  else Ans[q[i].id] += Query(1, q[i].z);
	  Ans[q[i].id] += mod;
	  Ans[q[i].id] %= mod;
   }
   for (int i = 1; i <= m; i++) printf("%lld\n", Ans[i]);
}

posted @ 2021-07-28 21:41  Dita  阅读(45)  评论(0)    收藏  举报