[BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】
题目链接: BZOJ - 3626
题目分析
考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就是从 y 到 Root 的路径上的点权和。
这个方法是可以叠加的,这是非常有用的一点。如果我们把 [l, r] 的每个点到 Root 的路径上所有点的权值 +1,再求出从 c 到 Root 的路径点权和,即为 [l, r] 中所有点与 c 的 LCA 的 Depth 和。
不仅满足可加性,还满足可减性,这就更好了!
那么我们就可以对每个询问 [l, r] 做一个差分,用 Query(r) - Query(l - 1) 作为答案。这样就有一种离线算法:将 n 个点依次操作,将其到 Root 的路径上的点权值 +1 ,然后如果这个点是某个询问的 l - 1 或 r ,就用那个询问的 c 求一下到 Root 的路径和,算入答案中。
Done!
写代码的时候忘记 % Mod 真是弱...
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector> using namespace std; const int MaxN = 50000 + 5, Mod = 201314; int n, m, Index;
int Father[MaxN], Depth[MaxN], Size[MaxN], Son[MaxN], Top[MaxN], Pos[MaxN];
int T[MaxN * 4], D[MaxN * 4], Len[MaxN * 4], Ans[MaxN], Q[MaxN]; vector<int> BA[MaxN], EA[MaxN]; struct Edge
{
int v;
Edge *Next;
} E[MaxN], *P = E, *Point[MaxN]; inline void AddEdge(int x, int y) {
++P; P -> v = y;
P -> Next = Point[x]; Point[x] = P;
} int DFS_1(int x, int Dep) {
Depth[x] = Dep;
Size[x] = 1;
int SonSize, MaxSonSize;
SonSize = MaxSonSize = 1;
for (Edge *j = Point[x]; j; j = j -> Next) {
SonSize = DFS_1(j -> v, Dep + 1);
if (SonSize > MaxSonSize) {
MaxSonSize = SonSize;
Son[x] = j -> v;
}
Size[x] += SonSize;
}
return Size[x];
} void DFS_2(int x) {
if (x == Son[Father[x]]) Top[x] = Top[Father[x]];
else Top[x] = x;
Pos[x] = ++Index;
if (Son[x] != 0) DFS_2(Son[x]);
for (Edge *j = Point[x]; j; j = j -> Next)
if (j -> v != Son[x]) DFS_2(j -> v);
} void Build_Tree(int x, int s, int t) {
Len[x] = t - s + 1;
D[x] = T[x] = 0;
if (s == t) return;
int m = (s + t) >> 1;
Build_Tree(x << 1, s, m);
Build_Tree(x << 1 | 1, m + 1, t);
} inline void Update(int x) {
T[x] = T[x << 1] + T[x << 1 | 1];
T[x] %= Mod;
} inline void Paint(int x, int Num) {
T[x] += Num * Len[x];
T[x] %= Mod;
D[x] += Num;
D[x] %= Mod;
} inline void PushDown(int x) {
if (D[x] == 0) return;
Paint(x << 1, D[x]);
Paint(x << 1 | 1, D[x]);
D[x] = 0;
} void Add(int x, int s, int t, int l, int r) {
if (l <= s && r >= t) {
Paint(x, 1);
return;
}
PushDown(x);
int m = (s + t) >> 1;
if (l <= m) Add(x << 1, s, m, l, r);
if (r >= m + 1) Add(x << 1 | 1, m + 1, t, l, r);
Update(x);
} void EAdd(int x) {
int fx;
fx = Top[x];
while (fx != 1) {
Add(1, 1, n, Pos[fx], Pos[x]);
x = Father[fx];
fx = Top[x];
}
Add(1, 1, n, Pos[1], Pos[x]);
} int Get(int x, int s, int t, int l, int r) {
if (l <= s && r >= t) return T[x];
int ret = 0;
PushDown(x);
int m = (s + t) >> 1;
if (l <= m) ret += Get(x << 1, s, m, l, r);
if (r >= m + 1) ret += Get(x << 1 | 1, m + 1, t, l, r);
return ret % Mod;
} int EGet(int x) {
int ret = 0, fx;
fx = Top[x];
while (fx != 1) {
ret += Get(1, 1, n, Pos[fx], Pos[x]);
ret %= Mod;
x = Father[fx];
fx = Top[x];
}
ret += Get(1, 1, n, Pos[1], Pos[x]);
return ret % Mod;
} int main()
{
scanf("%d%d", &n, &m);
int a, b, c;
for (int i = 2; i <= n; ++i) {
scanf("%d", &a);
++a;
Father[i] = a;
AddEdge(a, i);
}
DFS_1(1, 1);
Index = 0;
DFS_2(1);
Build_Tree(1, 1, n);
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d", &a, &b, &c);
++a; ++b; ++c;
Q[i] = c;
BA[a - 1].push_back(i);
EA[b].push_back(i);
}
for (int i = 1; i <= n; ++i) {
EAdd(i);
for (int j = 0; j < BA[i].size(); ++j)
Ans[BA[i][j]] -= EGet(Q[BA[i][j]]);
for (int j = 0; j < EA[i].size(); ++j)
Ans[EA[i][j]] += EGet(Q[EA[i][j]]);
}
for (int i = 1; i <= m; ++i) printf("%d\n", (Ans[i] + Mod) % Mod);
return 0;
}
[BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】的更多相关文章
- 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 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626 [LNOI2014]LCA ——树链剖分
思路转化很巧妙. 首先把询问做差分. 然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和. 这样和原问题是等价的,然后树链剖分+线段树就可以做了. #include <map ...
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...
- 洛谷 P4211 [LNOI2014]LCA (树链剖分+离线)
题目:https://www.luogu.org/problemnew/solution/P4211 相当难的一道题,其思想难以用言语表达透彻. 对于每个查询,区间[L,R]中的每个点与z的lca肯定 ...
- [LNOI2014]LCA 树链剖分 离线 前缀和 思维题
题目描述:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每 ...
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
随机推荐
- WCF服务发布到IIS时候,只能根据hostname访问,不能根据IP地址访问的解决办法
本文转载:http://www.cnblogs.com/deerbox/archive/2013/05/13/3076248.html 环境: VS2010 sp1,.net framework 4. ...
- TCP/IP(84) 详解
http://blog.csdn.net/zhangskd/article/category/873810
- IOS 播放动态Gif图片
图片分为静态和动态两种,图片的格式有很多种,在开发中比较常见的是.png和.jpg的静态图片,但有的时候在App中需要播放动态图片,比如.gif格式的小表情头像,在IOS中并没有提供直接显示动态图片的 ...
- Java基础知识强化之集合框架笔记27:ArrayList集合练习之去除ArrayList集合中的重复字符串元素
1. 去除ArrayList集合中的重复字符串元素(字符串内容相同) 分析: (1)创建集合对象 (2)添加多个字符串元素(包含重复的) (3)创建新的集合 (4)遍历旧集合,获取得到每一个元素 (5 ...
- sqlite使用blob类型存储/访问 结构体
/* open fire host and slora report data database */ int open_report_db(void) { ; char sql[SQL_COMMAN ...
- 论前端css初始化的重要性
新手,求喷,刚刚知道每个浏览器都有对 标签的初始化,就造成我们网站开发者开发的web程序,会在不同的网站上有不同的样式风格,这给用户带来了很不好的体验,这也是浏览器本身的原因造成的,这时候,我们不可能 ...
- java '相等'的比较.
我们知道对于操作符 "==",如果比较的是原生类型(primitive type),表示的是 '值本身'是否相等;而对于引用类型(reference type),表示的是 '对象的 ...
- asp.net发布和更新网站
我们一般使用ftp软件来更新网站,而更新之前的一个步骤就是发布项目.以下将讲解asp.net mvc如何发布网站. 打开项目 右键点击项目,选择“发布” 第一次发布前,需要配置一下发布配置文件:点击” ...
- Tomcat设置最佳线程数总结
最佳线程数: 性能压测的情况下,起初随着用户数的增加,QPS会上升,当到了一定的阀值之后,用户数量增加QPS并不会增加,或者增加不明显,同时请求的响应时间却大幅增加.这个阀值我们认为是最佳线程数. 为 ...
- Ubuntu14.04 Tomcat 安装过程记录
Ubuntu14.04 Tomcat 安装过程记录 检查java的版本 zhousp@ubuntu:~$ sudo java -version [sudo] password for zhousp: ...