很神奇的方法

感觉是有生之年都想不到正解的这种

考虑对i 到根的节点权值 + 1,则从根到z的路径和就是lca(i,z)的深度

所以依次把0 ~ n - 1的点权值 + 1

对于询问[l, r] 这个区间关于z 的深度和,就用(1, r) - (1, l - 1)的值表示

详见黄学长的博客啦

http://hzwer.com/3415.html

下面给出代码

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int N = + ;
const int MOD = ; struct Query {
int u, id, z, flag;
inline bool operator < (const Query &o) const {
return u < o.u;
}
} Q[N * ];
int n, q, tot, cnt;
int sz[N], dep[N], fa[N], hs[N], top[N], pos[N];
vector < int > E[N]; #define isdigit(x) (x >= '0' && x <= '9')
inline void read(int &ans) {
ans = ;
static char buf = getchar();
for (; !isdigit(buf); buf = getchar());
for (; isdigit(buf); buf = getchar())
ans = ans * + buf - '';
} void dfs1(int x, int d, int f) {
dep[x] = d; fa[x] = f;
sz[x] = ; hs[x] = -;
int tmp = ;
for (int i = ; i < E[x].size(); i++) {
int u = E[x][i];
dfs1(u, d + , x);
if (sz[u] > tmp)
hs[x] = u, tmp = sz[u];
sz[x] += sz[u];
}
} void dfs2(int x, int t) {
top[x] = t; pos[x] = ++tot;
if (hs[x] == -) return ;
dfs2(hs[x], t);
for (int i = ; i < E[x].size(); i++)
if (E[x][i] != hs[x])
dfs2(E[x][i], E[x][i]);
} int add[N * ], sum[N * ];
#define g(l, r) (l + r | l != r)
#define o g(l, r)
#define ls g(l, mid)
#define rs g(mid + 1, r) inline void pushDown(int l, int r) {
if (!add[o] || l == r) return ;
int mid = l + r >> ;
add[ls] += add[o];
sum[ls] += add[o] * (mid - l + );
add[rs] += add[o];
sum[rs] += add[o] * (r - mid);
add[o] = ;
} inline void pushUp(int l, int r) {
int mid = l + r >> ;
sum[o] = sum[ls] + sum[rs];
} void modify(int l, int r, int L, int R) {
if (l >= L && r <= R) {
sum[o] += r - l + ;
add[o]++;
return ;
}
pushDown(l, r);
int mid = l + r >> ;
if (L <= mid) modify(l, mid, L, R);
if (R > mid) modify(mid + , r, L, R);
pushUp(l, r);
} inline void modify(int x, int y) {
int f1 = top[x], f2 = top[y];
while (f1 != f2) {
if (dep[f1] < dep[f2])
swap(x, y), swap(f1, f2);
modify(, n, pos[f1], pos[x]);
x = fa[f1]; f1 = top[x];
}
if (dep[x] > dep[y]) swap(x, y);
modify(, n, pos[x], pos[y]);
} int query(int l, int r, int L, int R) {
if (l >= L && r <= R) return sum[o];
pushDown(l, r);
int mid = l + r >> ;
int ans = ;
if (L <= mid) ans += query(l, mid, L, R);
if (R > mid) ans += query(mid + , r, L, R);
return ans;
} inline int query(int x, int y) {
int f1 = top[x], f2 = top[y];
int ans = ;
while (f1 != f2) {
if (dep[f1] < dep[f2])
swap(x, y), swap(f1, f2);
ans = (ans + query(, n, pos[f1], pos[x])) % MOD;
x = fa[f1]; f1 = top[x];
}
if (dep[x] > dep[y]) swap(x, y);
ans = (ans + query(, n, pos[x], pos[y])) % MOD;
return ans;
} int ans1[N], ans2[N];
int main() {
read(n); read(q);
for (int i = ; i < n; i++) {
int x; read(x);
E[x].push_back(i);
}
dfs1(, , -); dfs2(, );
for (int i = ; i <= q; i++) {
int l, r, z;
read(l); read(r); read(z);
Q[++cnt] = (Query) {l - , i, z, };
Q[++cnt] = (Query) {r, i, z, };
}
sort(Q + , Q + cnt + );
int now = -;
for (int i = ; i <= cnt; i++) {
while (now < Q[i].u) ++now, modify(now, );
if (!Q[i].flag) ans1[Q[i].id] = query(Q[i].z, );
else ans2[Q[i].id] = query(Q[i].z, );
}
for (int i = ; i <= q; i++)
printf("%d\n", (ans2[i] - ans1[i] + MOD) % MOD);
return ;
}

bzoj3626: [LNOI2014]LCA (树链剖分)的更多相关文章

  1. [BZOJ3626] [LNOI2014]LCA(树链剖分)

    [BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...

  2. BZOJ3626[LNOI2014]LCA——树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

  3. bzoj3626 [LNOI2014]LCA——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 思路很巧妙,把区间换成前缀和相减: 把 l ~ r 到根路径上的点的点权都+1,然后 ...

  4. BZOJ3626 [LNOI2014]LCA 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3626 题意概括 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节 ...

  5. bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...

  6. 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

  7. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  8. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  9. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...

  10. BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

    http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...

随机推荐

  1. P5163 WD与地图 [整体二分,强连通分量,线段树合并]

    首先不用说,倒着操作.整体二分来做强连通分量,然后线段树合并,这题就做完了. // powered by c++11 // by Isaunoya #include <bits/stdc++.h ...

  2. Nessus 8.2.3无IP限制VM版虚拟机

    根据“西门吹雪”http://ximcx.cn/m/?post=151的文章自己下载配置的过程 VM版本>=12都行,我用的是VM14 下载地址 https://moehu-my.sharepo ...

  3. 最新NetSarang Xmanager安装激活-XShell、XFtp

    NetSarang Xmanager Enterprise 是一个简单易用的高性能的运行在 Windows 平台上的 X Server 软件.它能把远端 Unix/Linux 的桌面无缝地带到你的Wi ...

  4. Spring Cloud 5大组件

    服务发现——Netflix Eureka 客服端负载均衡——Netflix Ribbon 断路器——Netflix Hystrix 服务网关——Netflix Zuul 分布式配置——Spring C ...

  5. Visual Studio Code 搭建 C/C++开发环境方法总结

    之前看错资料踩了不少坑,先将可行经验总结如下: 1. 下载 Visual Studio Code 并安装.地址:https://code.visualstudio.com 2. 安装 C/C++插件与 ...

  6. js监听textarea 内容的变化,并计算内容的长度c

    html代码如下:   <div class="customer-message">   <label for="customerMessage&quo ...

  7. js对象赋值

    看到一道题: 根据包名,在指定空间中创建对象 效果 namespace({a: {test: 1, b: 2}}, 'a.b.c.d') 结果 {a: {test: 1, b: {c: {d: {}} ...

  8. json 的key值不能是变量

    var _key = name; var _value = 2; var params = { _key :_ value } _key 为变量 console.log(params); { _key ...

  9. weblogic的ssrf漏洞

    前言    什么是ssrf SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞. 一般情况下,SSRF攻击的目标 ...

  10. SQL语句中count(1)count(*)count(字段)用法的区别(转)

    SQL语句中count(1)count(*)count(字段)用法的区别 在SQL语句中count函数是最常用的函数之一,count函数是用来统计表中记录数的一个函数, 一. count(1)和cou ...