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那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
随机推荐
- vs2015配置cv文件,不用每次新建项目在配置
首先 选择空项目:新建完成后点击属性管理器 一定要确定你的环境是x86还是x64:我的是x64: 选择新的项目属性表 点击属性配置:配置cv的库目录.包含目录.链接器输入:可参考我前面的博文 Open ...
- 安全 - 内容安全策略(CSP)(未完)
威胁 跨站脚本攻击(Cross-site scripting) 跨站脚本攻击Cross-site scripting (XSS)是一种安全漏洞,攻击者可以利用这种漏洞在网站上注入恶意的客户端代码. 攻 ...
- PAT (Advanced Level) Practice 1036 Boys vs Girls (25 分)
This time you are asked to tell the difference between the lowest grade of all the male students and ...
- Linux网络课程学习第二天
第二天学习日志: 今天的课程主要内容: 详细介绍了如何安装红帽RHEL7的系统,并对RPM,Yum,Systemd和bash进行了简单介绍.
- float浮动造成高度塌陷的解决办法
Float是我们在页面布局中常用的,也是非常重要的一个属性,可以让页面布局变得更加灵活. 但是在继续学习之后,尤其是掌握了宽高自适应之后,我们常常会发现一个奇怪的现象:如果父元素没有设置高度,而子元素 ...
- Codeforces 1303E. Erase Subsequences 代码(dp 字符串压缩一维状态优化)
https://codeforces.com/contest/1303/problem/E #include<bits/stdc++.h> using namespace std; ; i ...
- C++ lvalue(左值)和rvalue(右值)
lvalue(左值)和rvalue(右值) 昨天写代码遇见一个这样的错误:{ "cannot bind non-const lvalue reference of type 'int& ...
- nginx技术
Nginx 处理高并发,单台服务器存在服务瓶颈 Nginx属于nio ,noblocking Io非阻塞式的 Apache属于Bio,Blocking IO 阻塞式的 安装部分 依赖安装:yum -y ...
- day:3.9基础复习
1.不要在模块之间相互调用,否则会出现麻绳现象,避免循环导入. ==:用来判断值是否相等(分别指向两个空间,但是空间里面的内容相同) is:判断指向是否相等. 例: a=[,,] b=[,,] a== ...
- 服务&软件&基础设施的区别
IT基础设施: 软件 硬件 数据库相关DBM 网络相关 networking(网络通信) 以上4个会出现的比较多 application people 上面的东西都能提供IT服务 一半的互联网公司都会 ...