题意:给出一个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. 第3章 接口与API设计 52条笔记

    第3章 接口与API设计 52条笔记 第15条: 用前缀避免命名空间冲突 Objective-C 没有其他语言那种内置的命名空间机制 .鉴于此,我们在起名时要设法避免潜在的命名冲突,否则很容易就重名了 ...

  2. dataTables去掉搜索框和每页多少条框体,解决Cannot reinitialise DataTable问题

    $('#example').DataTable({ searching:false, //去掉搜索框 bLengthChange:false,//去掉每页多少条框体 "language&qu ...

  3. ubuntu下安装mongo扩展

    安装openssl apt-get install openssl libssl-dev libssl0.9.8 libgtk2.0-dev 安装php-pear apt-get install ph ...

  4. PMP项目管理学习笔记(9)——范围管理

    关于范围管理的几个名词定义 产品范围:表示你和你的团队正在构建的产品或服务的特性和功能:产品范围与最终产品有关,包括产品的特性,组件和组成部分.人们谈论确定产品的范围时,大多都是在谈论确定产品的特性, ...

  5. CSS 循环动画效果。

    @-moz-keyframes revolving{ 0{ -moz-transform: rotate(0deg); -webkit-transform: rotate(0deg); } 25%{ ...

  6. 职业生涯手记——电视剧剧情O.O

    很多电视剧.偶像剧.电影里出现过一些场景,从来没想过狗血剧情是来源于现实.. 直到上周一开始,我慢慢相信了.. 事情是这样的. 我们小组有个组员H,从上周一开始他每天都去公司的座机电话接1~2个电话, ...

  7. CAD交互绘制直线(网页版)

    用户可以在CAD控件视区任意位置绘制直线. 主要用到函数说明: _DMxDrawX::DrawLine 绘制一个直线.详细说明如下: 参数 说明 DOUBLE dX1 直线的开始点x坐标 DOUBLE ...

  8. 产生多种anchor的代码讲解!很好!

    http://blog.csdn.net/xzzppp/article/details/52317863 源代码:https://github.com/rbgirshick/py-faster-rcn ...

  9. 性能测试,如何得到大量token,并保存在本地文件中

    需求:性能测试需要大量的token,模拟登陆 设计思路: 1.使用语言:python +request+正则匹配+写入本地 2.jmeter+函数助手+正则或者json/yaml+后置处理器beans ...

  10. 第4节 hive调优:动态分区调整问题

    执行如下截图中的语句时卡住了: 原因:yarn未启动,hive底层是要提交mapreduce到yarn上才能计算结果的. 之前启动yarn时,未执行jps查看是否已经启动.其实未启动成功: [root ...