【BZOJ3626】LCA(树上差分,树链剖分)
题意:给出一个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(树上差分,树链剖分)的更多相关文章
- 算法笔记--树的直径 && 树形dp && 虚树 && 树分治 && 树上差分 && 树链剖分
树的直径: 利用了树的直径的一个性质:距某个点最远的叶子节点一定是树的某一条直径的端点. 先从任意一顶点a出发,bfs找到离它最远的一个叶子顶点b,然后再从b出发bfs找到离b最远的顶点c,那么b和c ...
- 模板 树上求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 ...
- BZOJ 3626 LCA(离线+树链剖分+差分)
显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案.观察到,深度其实就是上面有几个已 ...
- 培训补坑(day8:树上倍增+树链剖分)
补坑补坑.. 其实挺不理解孙爷为什么把这两个东西放在一起讲..当时我学这一块数据结构都学了一周左右吧(超虚的) 也许孙爷以为我们是省队集训班... 好吧,虽然如此,我还是会认真写博客(保证初学者不会出 ...
- bzoj4034[HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6163 Solved: 2025[Submit][Stat ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(树链剖分)
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[Submit][Stat ...
- 4.12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量
LINK:duoxiao OJ LCA on Tree 题目: 一道树链剖分+树状数组的神题. (直接nQ的暴力有50. 其实对于树随机的时候不难想到一个算法 对于x的修改 暴力修改到根. 对于儿子的 ...
- BZOJ4034 [HAOI2015]树上操作 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...
- bzoj4034 树上操作 树链剖分+线段树
题目传送门 题目大意: 有一棵点数为 N 的树,以点 1 为根,且树点有权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有 ...
随机推荐
- 2019/05/13 JAVA虚拟机堆内存调优
-Xms4000m 堆内存初始值 * -Xmx4000m 堆内存最大值 * -XX:+PrintGCDetails 打印GC信息 * -XX:+UseSerialGC 使用串行GC * -XX:+Pr ...
- hashlib加密模块详解
1.hash是把任意长度的消息压缩到某一固定长度的数值的函数. hash主要用于安全加密,把一些不同长度的信息转化成杂乱的128位编码里,叫做hash值. hash就是把内容和内容地址之间找到一种映射 ...
- 详解 Handler 消息处理机制(附自整理超全 Q&A)
Android 为什么要用消息处理机制 如果有多个线程更新 UI,并且没有加锁处理,会导致界面更新的错乱,而如果每个更新操作都进行加锁处理,那么必然会造成性能的下降.所以在 Android 开发中,为 ...
- 初试springWebMVC
最近在尝试配置SpringMVC,发现各种坑. 首先遇到了这个问题. 'component-scan' and its parser class [org.springframework.contex ...
- fsck和badlocks
fsck可以检查好几种不同的文件系统,fsck只是一个中和程序而已,个别的文件系统检查程序都在/sbin中,可以使用ls -l /sbin/fsck* -A 按照/etc/fstab的内容,将所有的设 ...
- ubuntu下安装方式汇总
apt-get 可辅助通过 apt-cache search curl | grep php 查找已支持的插件,然后通过下面apt-get下载安装,例: apt-get install php5-cu ...
- Python 中print 和return 的区别
1.print() print()函数的作用是输出数据到控制台,就是打印在你能看到的界面上. 2.return return语句[表达式]退出函数,选择性地向调用方返回一个表达式.不带参数值的retu ...
- vue点击时动态改变样式 ------- 最简单的方法
vue点击时动态改变样式 template中 <li :class="{ active:index==isActive }" @click="changeValue ...
- CAD交互绘制多段线(网页版)
多段线又被称为多义线,表示一起画的都是连在一起的一个复合对象,可以是直线也可以是圆弧并且它们还可以加不同的宽度. 主要用到函数说明: _DMxDrawX::DrawLine 绘制一个直线.详细说明如下 ...
- Python打包成exe,pyc
D:\mypython\path\ C:\Python27\Scripts\pyinstaller.exe -w mypython.py # Python打包成exe D:\mypython\path ...