【树链剖分 差分】bzoj3626: [LNOI2014]LCA
把LCA深度转化的那一步还是挺妙的。之后就是差分加大力数据结构了。
Description
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
0
0
1
1
1 4 3
1 4 2
Sample Output
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题目分析
我的做法&图片分析
由于树的标号是随便标的,所以这里的$[l,r]$区间操作在树上并没有什么大的特殊意义。
注意到如果$z$是给定的话,那么由于答案可减,我们可以对于序列来分块。
当然分块只是一种想法,再来挖掘一下$z$给定情况的性质。

这里求4和7的LCA。自然,LCA就是两点到根节点的第一个公共节点。不过这幅图可能还没看出什么。

这幅图里7号节点是z,4,6,8节点是与z节点查询的节点。我们把与z节点查询的节点都沿路径向根方向+1。
这样只需要查询z节点到根节点的路径权值和就能算出所有LCA的深度之和了。
注意到这样处理之后,预处理的信息对于任意的z都适用了。
至于题目要求的“根节点深度为1”,正好可以让我们把边权化为点权,做起来也更加方便。
更理论化的题解
在黄学长博客上看到一篇更加严谨的题解:
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。
(大力数据结构~)
#include<bits/stdc++.h>
const int MO = ;
const int maxn = ;
const int maxm = ; struct node
{
int fa,top,son,tot;
}a[maxn];
struct QRs
{
int x,id,opt;
QRs(int a=, int b=, int c=):x(a),id(b),opt(c) {}
bool operator < (QRs a) const
{
return x < a.x;
}
}q[maxn<<];
int chain[maxn],chTot;
int f[maxn<<],add[maxn<<];
int edges[maxm],nxt[maxm],head[maxn],edgeTot;
int ansAdd[maxn],ansDel[maxn],qr[maxn];
int n,m,tot; int read()
{
char ch = getchar();
int num = ;
bool fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = ;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
if (fl) num = -num;
return num;
}
void addedge(int u, int v)
{
edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
}
void dfs1(int x, int fa)
{
a[x].fa = fa, a[x].son = -, a[x].tot = ;
for (int i=head[x]; i!=-; i=nxt[i])
{
int v = edges[i];
dfs1(v, x), a[x].tot += a[v].tot;
if (a[x].son==-||a[a[x].son].tot < a[v].tot)
a[x].son = v;
}
}
void dfs2(int x, int top)
{
chain[x] = ++chTot, a[x].top = top;
if (a[x].son==-) return;
dfs2(a[x].son, top);
for (int i=head[x]; i!=-; i=nxt[i])
if (edges[i]!=a[x].son)
dfs2(edges[i], edges[i]);
}
void pushup(int x)
{
f[x] = (f[x<<]+f[x<<|])%MO;
}
void pushdown(int x, int l, int r)
{
if (add[x]){
add[x<<] += add[x], add[x<<|] += add[x];
f[x<<] += l*add[x], f[x<<|] += r*add[x];
f[x<<] %= MO, f[x<<|] %= MO;
add[x] = ;
}
}
void update(int rt, int L, int R, int l, int r)
{
if (L <= l&&r <= R){
add[rt]++, f[rt] = (f[rt]+r-l+)%MO;
return;
}
int mid = (l+r)>>;
pushdown(rt, mid-l+, r-mid);
if (L <= mid) update(rt<<, L, R, l, mid);
if (R > mid) update(rt<<|, L, R, mid+, r);
pushup(rt);
}
void updateChain(int x, int y)
{
while (a[x].top!=a[y].top)
{
update(, chain[a[x].top], chain[x], , n);
x = a[a[x].top].fa;
}
update(, chain[y], chain[x], , n);
}
int query(int rt, int L, int R, int l, int r)
{
if (L <= l&&r <= R) return f[rt];
int mid = (l+r)>>, ret = ;
pushdown(rt, mid-l+, r-mid);
if (L <= mid) ret += query(rt<<, L, R, l, mid);
if (R > mid) ret += query(rt<<|, L, R, mid+, r);
return ret%MO;
}
int queryChain(int x, int y)
{
int ret = ;
while (a[x].top!=a[y].top)
{
ret += query(, chain[a[x].top], chain[x], , n);
x = a[a[x].top].fa;
}
ret += query(, chain[y], chain[x], , n);
return ret%MO;
}
int main()
{
memset(head, -, sizeof head);
n = read(), m = read();
for (int i=; i<n; i++) addedge(read(), i);
for (int i=; i<=m; i++)
{
q[++tot] = QRs(read()-, i, ), q[++tot] = QRs(read(), i, );
qr[i] = read();
}
std::sort(q+, q+tot+);
dfs1(, -);
dfs2(, );
int now = -;
for (int i=; i<=tot; i++)
{
while (now < q[i].x)
updateChain(++now, );
int id = q[i].id;
if (q[i].opt)
ansAdd[id] = queryChain(qr[id], );
else ansDel[id] = queryChain(qr[id], );
}
for (int i=; i<=m; i++)
printf("%d\n",(ansAdd[i]-ansDel[i]+MO)%MO);
return ;
}
END
【树链剖分 差分】bzoj3626: [LNOI2014]LCA的更多相关文章
- 树链剖分与倍增求LCA
树链剖分与倍增求\(LCA\) 首先我要吐槽机房的辣基供电情况,我之前写了一上午,马上就要完成的时候突然停电,然后\(GG\)成了送链剖分 其次,我没歧视\(tarjan LCA\) 1.倍增求\(L ...
- BZOJ 3626 LCA(离线+树链剖分+差分)
显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案.观察到,深度其实就是上面有几个已 ...
- HDU 5452——Minimum Cut——————【树链剖分+差分前缀和】ACdream 1429——Diversion——————【树链剖分】
Minimum Cut Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)Tota ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 树链剖分+差分前缀和优化
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 说明 思路 AC代码 优化 优化后AC代码 总结 题面 题目链接 P3258 [JLOI2 ...
- 【线段树 树链剖分 差分 经典技巧】loj#3046. 「ZJOI2019」语言【未完】
还是来致敬一下那过往吧 题目分析 先丢代码 #include<bits/stdc++.h> ; ; ; struct node { int top,son,fa,tot; }a[maxn] ...
- 树链剖分(附带LCA和换根)——基于dfs序的树上优化
.... 有点懒: 需要先理解几个概念: 1. LCA 2. 线段树(熟练,要不代码能调一天) 3. 图论的基本知识(dfs序的性质) 这大概就好了: 定义: 1.重儿子:一个点所连点树size最大的 ...
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- 【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA
引用题解: http://blog.csdn.net/popoqqq/article/details/38823457 题目大意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深 ...
- 【BZOJ3626】LCA(树上差分,树链剖分)
题意:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给 ...
随机推荐
- IT兄弟连 JavaWeb教程 JSP经典面试题
1.JSP标准提供了三种独立的向JSP添加Java代码的技术,请列举. <% %>JSP程序代码块,内部可以直接嵌入Java代码. <%! %>JSP声明区,内部可以声明变量和 ...
- 17..userinfo.txt 文件中存放以下结构:
alex:alex3714 wusir:123456 meet:meet123 1.让用户选择: 1.注册 2.登录 2.用户选择注册就将账号和密码添加到userinfo.txt中,如果用户名存在就提 ...
- 关于Dictionary的优化用法
今天突然想到了解一下Dictionary,于是在博客园上看到了一篇关于用TryGetValue的文章,原来用TryGetValue要比用ContainsKey更快,快一倍.
- Excel 通过pl/sql导入到数据库 文本导入器 odbc导入器
Excel 通过pl/sql导入到数据库 第一种方法:文本导入器 1.准备Excel导入数据 jc.xls 2.把 jc.xls 文件 改为 jc.csv文件 3.在数据库里建一张jc表(FLH ...
- tera term超级终端
一款Window上的虚拟终端工具,它同时支持串口连接和网络连接,而对于网络连接它支持Telnet和SSH协议.最关键的是Tera Term支持自己的脚本语言,即TTL(Tera Term Langua ...
- 将Object转换成Dictionary方法
如果Object是Dictionary类型,直接返回 如果Object是NameValueCollection类型,则添加到Dictionary里 如果Object是Hashtable类型,添加到Di ...
- Java-IDEA环境搭建swagger
1.项目POM导入包(使用Maven管理的代码) 2.POM文件导入包 <dependencyManagement> <dependencies> <dependency ...
- 浅析ES6中的iterator
1.iterator迭代器必须保证其遍历终止条件可控,否则会形成死循环demo: //会用到iterator接口的场合 //1.for...of循环 //2. ...解构表达式 const obj = ...
- Java 图形界面开发--图文并茂建立学生管理系统
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/50932501 冷血之心的博客) 图形用户界面(Graphics U ...
- 解析 MFC 中的 FromHandle
MFC 对 Windows API 进行了封装,在很多方面都会提供便利.用 FromHandle 返回零时对象的指针,就可以调用各种类的方法.临时对象会在 OnIdle 中销毁.这里对 FromHan ...