很神奇的方法

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

考虑对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. 收录了老师发的几个 download ebook and paper 的 webpage

    Library Genesis (important) http://zh.b-ok.org National Academic Press OpenStax CNX gen.lib.rus.ec l ...

  2. python之路(集合,深浅copy,基础数据补充)

    一.集合:类似列表,元组的存储数据容器,不同点是不可修改,不可重复.无序排列. 1.创建集合: (1).set1 = {'abby', 'eric'} result:{'eric', 'abby'} ...

  3. ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理

    原文:https://www.stevejgordon.co.uk/httpclientfactory-using-polly-for-transient-fault-handling发表于:2018 ...

  4. poj2387- Til the Cows Come Home(最短路板子题)

    题目描述 Description Bessie is out in the field and wants to get back to the barn to get as much sleep a ...

  5. [hive]case 语句中字符串匹配

    当使用case when时,有时会需要对某个字段做子串匹配.如果是在where条件中,我们会直接使用 like '%xx%'来匹配,但case when语句不行 这时需要使用instr函数 examp ...

  6. C++-蓝桥杯-入门训练

    Fibonacci数列,快速幂 #include <cstdio> ][];}; ,MOD=; Matrix A,B,O,I; Matrix Mul(Matrix A,Matrix B){ ...

  7. 安装 centos8.1

    阿里云镜像下载链接 http://mirrors.aliyun.com/centos/8.1.1911/isos/x86_64/ 选择 CentOS-8.1.1911-x86_64-dvd1.iso ...

  8. Python 类方法、实例方法、静态方法的使用与及实例

    类方法 使用装饰器@classmethod 第一个参数必须是当前类对象,该参数名一般约定为“cls” (可修改但不建议)通过他来传递类的属性和方法(不能传实例的属性和方法) 调用:实例对象和类对象多可 ...

  9. Python中pip的使用

    1.pip安装模块 pip install 模块名称 -i 安装源 pip install requests -i https://mirrors.aliyun.com/pypi/simple/

  10. 148.CSRF攻击原理分析、防御、装饰器、中间件、IFrame以及js实现csrf攻击

    CSRF攻击概述: CSRF(Cross Site Request Forgery 跨站域请求伪造)是一种网站攻击的方式,它在2007年曾被列为互联网20大安全隐患之一.其他的安全隐患,比如SQL脚本 ...