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那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
随机推荐
- Deepin Linux 升级wine应用
前提是升级已经安装的wine应用 参考: 微信升级 mkdir /tmp/wechat cd /tmp/wechat wget https://dldir1.qq.com/weixin/Windows ...
- Deepin Linux折腾输入法
Deepin Linux 别折腾输入法了 , 很容易把自己整残了 Deepin 自带五笔拼音输入法 , 平时撸码用完全够了 . 但今天突然快捷键不好用了.怎么都切不了英文输入 . 切输入法也不能切到英 ...
- 用 ArcMap 发布 ArcGIS Server Feature Server Feature Access 服务 SQL Server版
1. 安装Desktop, 2. 安装ArcGIS Server 3. 安装SQLServer2017 4. ArcMap 中 Catalog 中注册ArcGIS Server 5. System T ...
- 1级搭建类110-Oracle 18c SI FS(Windows Server 2019)公开
Oracle 18c 单实例文件系统在Windows Server 2019上的安装 在线查看
- C# Dynamic与Newtonsoft.Json的应用
C#中Dynamic关键字 dynamic关键字和动态语言运行时(DLR)是.Net 4.0中新增的功能. 什么是"动态"? 编程语言有时可以划分为静态类型化语言和动态类型化语言. ...
- VSCode C语言编程(二)新建项目及编译
添加工作区: 把文件夹在工作区删除: 把HelloWorld模板文件夹解压到工作目录 模板下载(代码解释请看模板里的注释) 添加项目文件夹: 编辑器打开的文件必须与main.c同目录 点击右边编译图标 ...
- H3C ARP配置
一.ARP简介 ARP(Address Resolution Protocol,地址解析协议)是将IP地址解析为以太网MAC地址(或称物理地址)的协议. 在网络中,当主机或其它网络设备有数据要发送给另 ...
- Wannafly Camp 2020 Day 2F 采蘑菇的克拉莉丝 - 树链剖分
如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...
- abp demo运行1
1.从官方网站下载demo 如下: https://aspnetboilerplate.com/Templates 填写响应的信息,下载demo 2.vs2017打开demo,如下图: 3.安装.ne ...
- (转)git使用规范
转自:http://www.ruanyifeng.com/blog/2015/08/git-use-process.html 团队开发中,遵循一个合理.清晰的Git使用流程,是非常重要的. 否则,每个 ...