[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, ...
随机推荐
- APP安全环节缺失,手游运营商怎样应对APP破解困境
2013年手游行业的规模与收入均实现了大幅增长,发展势头强劲.然而,在手游快速发展的同一时候,因为监管.审核等方面存在着漏洞,手机游戏软件被破解后注入恶意代码.盗取用户財产.窃取用户设备信息的现象屡见 ...
- 手机相机ISO是什么
要说什么是ISO还要从传统胶片相机说起,ISO被 称为感光度,它是衡量传统相机所使用胶片感光速度的国际统一指标,其数值反映了胶片感光时的速度(其实是银元素与光线的光化学反应速率).而对于现在并不 使用 ...
- PHP面向对象之旅:抽象类继承抽象类(转)
可以理解为对抽象类的扩展 抽象类继承另外一个抽象类时,不用重写其中的抽象方法.抽象类中,不能重写抽象父类的抽象方法.这样的用法,可以理解为对抽象类的扩展. 下面的例子,演示了一个抽象类继承自另外一个抽 ...
- SDL 实现透明悬浮窗
最近一直想用SDL实现弹幕功能,但是一直没法实现悬浮窗和透明背景功能. 在一个老外的博客上发现了思路:EthioProgrammer: Applying transparency using win3 ...
- Bash远程文件传输命令scp
备份远程文件(远程——>本地) scp -r 远程用户名@ip:文件绝对路径 本地绝对路径 还原远程文件(本地——>远程) scp -r 本地路径 远程用户名@ip:远程绝对路径 如果SS ...
- Eclipse配置使用web.xml
为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/3792664.html ...
- Topcoder SRM 661 (Div.1) 250 MissingLCM - 数论
[题意] 给你一个数N(1<=N<=10^6),要求最小的M(M>N),使得lcm(n+1,n+2,...m)=lcm(1,2,3,...,m) [思路] 手速太慢啦,等敲完代码的时 ...
- EntityFramework 中生成的类加注释
EF5在生成实体类时获取不到数据库中表的说明字段,需要使用单独的t4模板来获取 下载文件 将文件与edmx 放同一文件夹 1.在生成类的t4模板中加入 <#@ include file=&quo ...
- CentOS安装memcached及配置php的memcache扩展
遇到的问题: 这个问题主要是linux服务器安装memcached服务后,phpinfo信息没有memcache扩展,所以主要是给php安装memcache扩展,教程中是安装memcache扩展,我认 ...
- WCF系列学习5天速成
看到一篇比较好的基础wcf学习博客,分享给大家:http://www.cnblogs.com/huangxincheng/archive/2011/10/23/2221845.html