题意:给出一个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的最近公共祖先的深度之和)

n<=50000

思路:From THU爷 LYY

我们考虑这样一种暴力:

对于dep[lca(i,j)],可以将0~i路径上的点的权值+1,那么答案就是0~j路径上的点的权值之和。

因此对于[l,r]区间,可以将每个点到根节点的权值+1,那么答案ans[l,r]就是0~z路径上的点的权值之和。

显然ans[l,r]=ans[1,r]-ans[1,l-1]。

那么可以树链剖分,然后将0~n-1这n个点插入线段树中,顺便求出答案,复杂度O(nlogn^2)。

 const mo=;
var t:array[..]of record
a,s,l:longint;
end;
head,vet,next,head1,vet1,next1,c,d,
size,son,tid,id,top,flag,dep,fa,ans:array[..]of longint;
n,q,i,j,l,r,z,tot,f,v,time,e:longint; procedure add(a,b:longint);
begin
inc(tot);
next[tot]:=head[a];
vet[tot]:=b;
head[a]:=tot;
end; procedure swap(var x,y:longint);
var t:longint;
begin
t:=x; x:=y; y:=t;
end; procedure addq(a,b,c1,d1:longint);
begin
inc(tot);
next1[tot]:=head1[a];
vet1[tot]:=b;
c[tot]:=c1;
d[tot]:=d1;
head1[a]:=tot;
end; procedure dfs1(u:longint);
var e,v,maxsize,t:longint;
begin
flag[u]:=; size[u]:=; son[u]:=; t:=;
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then
begin
dep[v]:=dep[u]+;
dfs1(v);
size[u]:=size[u]+size[v];
if size[v]>t then
begin
t:=size[v]; son[u]:=v;
end;
e:=next[e];
end;
end;
end; procedure dfs2(u,ance:longint);
var e,v:longint;
begin
flag[u]:=; inc(time); tid[u]:=time; id[time]:=u; top[u]:=ance;
if son[u]> then dfs2(son[u],ance);
e:=head[u];
while e<> do
begin
v:=vet[e];
if flag[v]= then dfs2(v,v);
e:=next[e];
end;
end; procedure hash(var x:longint);
begin
if x>=mo then x:=x mod mo;
end;
procedure pushdown(x:longint);
var l,r,tmp:longint;
begin
tmp:=t[x].a;
if tmp= then exit;
l:=x<<; r:=l+;
t[l].a:=t[l].a+tmp; hash(t[l].a);
t[r].a:=t[r].a+tmp; hash(t[r].a);
t[l].s:=t[l].s+t[l].l*tmp; hash(t[l].s);
t[r].s:=t[r].s+t[r].l*tmp; hash(t[r].s);
t[x].a:=;
end; procedure pushup(x:longint);
var l,r:longint;
begin
l:=x<<; r:=l+;
t[x].s:=t[l].s+t[r].s; hash(t[x].s);
end; procedure build(l,r,p:longint);
var mid:longint;
begin
t[p].l:=r-l+;
if l=r then exit;
mid:=(l+r)>>;
build(l,mid,p<<);
build(mid+,r,p<<+);
end; function query(l,r,x,y,p:longint):longint;
var mid:longint;
begin
if (l>=x)and(r<=y) then exit(t[p].s);
mid:=(l+r)>>;
pushdown(p);
query:=;
if x<=mid then query:=query+query(l,mid,x,y,p<<);
if y>mid then query:=query+query(mid+,r,x,y,p<<+);
// if query>=mo then query:=query-mo;
hash(query);
end; procedure update(l,r,x,y,p:longint);
var mid:longint;
begin
if (l>=x)and(r<=y) then
begin
inc(t[p].a);
// if t[p].a>=mo then t[p].a:=t[p].a-mo;
hash(t[p].a);
t[p].s:=t[p].s+t[p].l;
hash(t[p].s);
// if t[p].s>=mo then t[p].s:=t[p].s-mo;
exit;
end;
mid:=(l+r)>>;
pushdown(p);
if x<=mid then update(l,mid,x,y,p<<);
if y>mid then update(mid+,r,x,y,p<<+);
pushup(p);
end; procedure change(k:longint);
begin
while top[k]<> do
begin
update(,n,tid[top[k]],tid[k],);
k:=fa[top[k]];
end;
update(,n,,tid[k],);
end; function clac(k:longint):longint;
begin
clac:=;
while top[k]<> do
begin
clac:=clac+query(,n,tid[top[k]],tid[k],);
// if clac>=mo then clac:=clac-mo;
hash(clac);
k:=fa[top[k]];
end;
clac:=clac+query(,n,,tid[k],);
// if clac>=mo then clac:=clac-mo;
hash(clac);
end; begin
assign(input,'bzoj3626.in'); reset(input);
assign(output,'bzoj3626.out'); rewrite(output);
readln(n,q);
for i:= to n do
begin
read(fa[i]); inc(fa[i]);
add(fa[i],i);
end;
dfs1();
fillchar(flag,sizeof(flag),);
dfs2(,);
tot:=;
for i:= to q do
begin
readln(l,r,z);
inc(l); inc(r); inc(z);
addq(l-,i,z,-);
addq(r,i,z,);
end;
build(,n,);
for i:= to n do
begin
change(i);
e:=head1[i];
while e<> do
begin
v:=vet1[e]; j:=c[e]; f:=d[e];
ans[v]:=(ans[v]+f*clac(j) mod mo+mo) mod mo;
e:=next1[e];
end;
end;
for i:= to q do writeln(ans[i]); close(input);
close(output);
end.

【BZOJ3626】LCA(树上差分,树链剖分)的更多相关文章

  1. 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分

    树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...

  2. 模板 树上求LCA 倍增和树链剖分

    //233 模板 LCA void dfs(int x,int f){ for(int i=0;i<E[x].size();i++){ int v = E[x][i]; if(v==f)cont ...

  3. BZOJ 3626 LCA(离线+树链剖分+差分)

    显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案.观察到,深度其实就是上面有几个已 ...

  4. 培训补坑(day8:树上倍增+树链剖分)

    补坑补坑.. 其实挺不理解孙爷为什么把这两个东西放在一起讲..当时我学这一块数据结构都学了一周左右吧(超虚的) 也许孙爷以为我们是省队集训班... 好吧,虽然如此,我还是会认真写博客(保证初学者不会出 ...

  5. bzoj4034[HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6163  Solved: 2025[Submit][Stat ...

  6. 洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  7. bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Stat ...

  8. 4.12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量

    LINK:duoxiao OJ LCA on Tree 题目: 一道树链剖分+树状数组的神题. (直接nQ的暴力有50. 其实对于树随机的时候不难想到一个算法 对于x的修改 暴力修改到根. 对于儿子的 ...

  9. BZOJ4034 [HAOI2015]树上操作 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...

  10. bzoj4034 树上操作 树链剖分+线段树

    题目传送门 题目大意: 有一棵点数为 N 的树,以点 1 为根,且树点有权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有 ...

随机推荐

  1. 转 Java 208道面试题及部分答案 补充部分答案

    转自https://www.cnblogs.com/chen1005/p/10481102.html   ---恢复内容开始--- 一.Java 基础 1.JDK 和 JRE 有什么区别? 答:JRE ...

  2. 【学习笔记】深入理解js原型和闭包(4)——隐式原型

    注意:本文不是javascript基础教程,如果你没有接触过原型的基本知识,应该先去了解一下,推荐看<javascript高级程序设计(第三版)>第6章:面向对象的程序设计. 上节已经提到 ...

  3. 在CentOS上把Git从1.7.1升级到1.7.12.4

    在CentOS上把Git从1.7.1升级到1.7.12.4 摘要:本文记录了在CentOS 6.3上,把Git从1.7.1升级到1.7.12.4的过程. 1. 概述 在我做的一个项目中,最近我对生产服 ...

  4. qt5.8使用qwebenginview注意事项

    环境qt5.8,vs2015(ui.webview必须要先show出来,不然加载不成功) 1.项目属性,c/c++,常规,附加包含目录,新增: $(QTDIR)\include\QtWebChanne ...

  5. hdu 2192 MagicBuilding

    Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...

  6. 使用Recast.AI创建具有人工智能的聊天机器人

    很多SAP顾问朋友们对于人工智能/机器学习这个话题非常感兴趣,也在不断思考如何将这种新技术和SAP传统产品相结合.Jerry之前的微信公众号文章C4C和微信集成系列教程曾经介绍了Partner如何利用 ...

  7. JDO

    JDO 编辑 本词条缺少名片图,补充相关内容使词条更完整,还能快速升级,赶紧来编辑吧! JDO(Java Data Object )是Java对象持久化的新的规范,也是一个用于存取某种数据仓库中的对象 ...

  8. Python 循环结构语句

    1.for循环:计次循环 2.while循环:条件循环 3.嵌套循环 4.跳转语句 一.for循环的使用 1.进行数值循环 利用数值循环输出三次‘你好’: >>> for i in ...

  9. c语言 错误记录

    1.预处理错误 #include <>   //系统内部的 #include ""   // 自定义的 遇到 not find------解决方案:gcc -I 跟查找 ...

  10. (转)关于treap的板子理解

    关于treap的板子理解: 关于结构体的定义:(一般平衡树无法理解的变量名):v:节点的值:size:子节点的个数(包括自己):cnt:相同的值的副本数:l:左儿子:r:右儿子: 右旋:父亲变成左儿子 ...