题意:给出一个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. P3371 【模板】单源最短路径

    题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...

  2. jQuery Validate自定义各种验证方法(转)

    一.封装自定义验证方法-validate-methods.js /***************************************************************** j ...

  3. mongoDB学习初步总结

    What? 最受欢迎的非关系型数据库之一.面向文档的数据库,在存储乎数据方面与关系型数据库有着本质的区别. Why? 简单易用 对多变的业务需求,适应性强于SQL型DB 性能 复制 索引 分片 丰富的 ...

  4. 语音行业技术领先者Nuance诚招ASR/NLP研发工程师和软件工程师

    Nuance is a leading provider of voice and language solutions for businesses and consumers around the ...

  5. swift Equatable 函数签名的测试

    struct Degoo:Equatable { var lex:String var pex:String static func == (left:Degoo, right:Degoo) -> ...

  6. Architecture:架构 元素与关系

    http://www.iso-architecture.org/42010/cm/ Systems have architectures. In the Standard, the architect ...

  7. hql语法001

    1. import java.util.List; import org.hibernate.*; import org.junit.Test; import cn.jbit.hibernatedem ...

  8. JS怎么创建一个类?

    15. JS怎么创建一个类? 方式1 : var obj = new Object(); 方式2 : var obj = {}; 16.JS的typeof返回哪些数据类型? string.number ...

  9. python基础一 day2 数据类型

    int:        bool: 类型转换: str到int有条件,str必须是数字, "123e"是错误的 bool转换为int类型,需要int(x)  结果:  结果: 空字 ...

  10. Jquery中children与find之间的区别

    <table id="tb"> <tr> <td>0</td> <td>1</td> <td>2 ...