bzoj3626: [LNOI2014]LCA (树链剖分)
很神奇的方法
感觉是有生之年都想不到正解的这种
考虑对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 (树链剖分)的更多相关文章
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- BZOJ3626[LNOI2014]LCA——树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- bzoj3626 [LNOI2014]LCA——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 思路很巧妙,把区间换成前缀和相减: 把 l ~ r 到根路径上的点的点权都+1,然后 ...
- BZOJ3626 [LNOI2014]LCA 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3626 题意概括 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节 ...
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
随机推荐
- Java第二节课总结
Java的基本运行单位是类.类由数据成员和函数成员组成.变量的类型之间可以相互转换.String是一个类.static代表静态变量. 运行结果: false false ...
- sqlmap注入基本教程
附上一个别人总结的:https://www.cnblogs.com/ichunqiu/p/5805108.html 一套基础的sqlmap语句: python sqlmap.py -u "h ...
- mysql 数据库中存在重复记录,删除保留其中一条
DELETE FROM people WHERE peopleName IN ( SELECT peopleName FROM people GROUP BY peopleName HAVING ) ...
- StarUML 2下载、安装、破解全过程
StarUML官方下载地址: http://staruml.io/download 破解: 1.使用Editplus或者Notepad++等特殊的文本编辑器打开 安装位置下/www/lic ...
- AI机器人最高等级
AI机器人最高等级 题目描述 在小朱朱的游戏世界里,有n个AI机器人. 他们相互之间可以进行PK,胜方存活且升一级,负方直接淘汰. 高等级AI必定战胜低等级AI,同等级AI的PK结果必定一胜一负,且规 ...
- vue之项目打包部署到服务器
这是今年的第一篇博客.整理一下vue如何从项目打包到部署服务器,给大家做下分享,希望能给大家带来或多或少的帮助,喜欢的大佬们可以给个小赞,如果有问题也可以一起讨论下. 第一步:这是很关键的一步.打开项 ...
- Power Strings[poj2406]题解
Power Strings Description - Given two strings a and b we define ab to be their concatenation. For ex ...
- koa文档笔记
请求 get ctx.request.query // 查询对象 ctx.request.querystring // 查询字符串 ctx.query // 查询对象 ctx.querystring ...
- JavaScript 13 Ajax技术(未完)
<body> <!-- 添加文档主体内容 --> <header> <nav>JavaScript - Ajax - 读取XML文件</nav&g ...
- vue的$nextTick
https://segmentfault.com/a/1190000012861862 简单来说:如果你修改了某个dom中的数据,视图并不会立即更新.Vue 实现响应式并不是数据发生变化之后 DOM ...