http://www.lydsy.com/JudgeOnline/problem.php?id=3626

LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的。
我如果现场写,很难想出来这种题,是时候复习一波离线算法泡脑子了。(没有暴力分的题,想不出来正解就爆零,太可怕了)
排序后离线操作通过前缀和计算答案,题解是hzwer的博客上复制的

直接引用清华爷gconeice的题解吧

显然,暴力求解的复杂度是无法承受的。

考虑这样的一种暴力,我们把 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<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=;
const long long modn=;
const long long minf=<<;
int n,m;
struct nod{
int y,next;
}e[maxn];int head[maxn]={},tot=;
int fa[maxn]={},top[maxn]={},pos[maxn]={},kid[maxn]={},dep[maxn]={};
void init(int x,int y){
e[++tot].y=y;e[tot].next=head[x];head[x]=tot;
}
int dfs1(int x){
int y,hug=,siz,tsn=;dep[x]=dep[fa[x]]+;
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
if(y==fa[x])continue;
siz=dfs1(y);
if(siz>hug)hug=siz,kid[x]=y;
tsn+=siz;
}return tsn;
}
void dfs2(int x,int pa){
int y;top[x]=pa;pos[x]=++tot;
if(kid[x])dfs2(kid[x],pa);
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
if(y==kid[x]||y==fa[x])continue;
dfs2(y,y);
}
}
struct seg{
long long sum,w,l,r;
seg(){sum=l=r=;}
}t[maxn*];
void build(int x,int l,int r){
t[x].l=l;t[x].r=r;
if(l==r)return;
int mid=(l+r)/;
build(x*,l,mid);
build(x*+,mid+,r);
}
void pushup(int x){
if(t[x].r>t[x].l)t[x].sum=t[x*].sum+t[x*+].sum;
t[x].sum+=(t[x].r-t[x].l+)*t[x].w;
}
void add(int x,int l,int r){
if(l<=t[x].l&&t[x].r<=r){
if(t[x].l==t[x].r)t[x].sum+=;
else {t[x].w+=;pushup(x);}
return;
}
int mid=(t[x].l+t[x].r)/,ls=x*,rs=x*+;
if(r>mid) add(rs,l,r);
if(l<=mid) add(ls,l,r);
pushup(x);
}
long long sum(int x,int l,int r,int w){
if(l<=t[x].l&&t[x].r<=r)return t[x].sum+w*(t[x].r-t[x].l+);
int mid=(t[x].l+t[x].r)/,ls=x*,rs=x*+;long long tsn=;
if(l<=mid) tsn+=sum(ls,l,r,w+t[x].w);
if(r>mid) tsn+=sum(rs,l,r,w+t[x].w);
return tsn;
}
long long doit(int x){
int a=top[x];long long tsn=;
for(;a!=;){
tsn+=sum(,pos[a],pos[x],);
x=fa[a];a=top[x];
}
tsn+=sum(,pos[a],pos[x],);
return tsn;
}
void datup(int x){
int a=top[x];
for(;a!=;){
add(,pos[a],pos[x]);
x=fa[a];a=top[x];
}
add(,pos[a],pos[x]);
}
struct lcc{
int num;
int z;int id;
long long ans;
}q[maxn*];
bool cmp1(lcc aa,lcc bb){return aa.num<bb.num;}
bool cmp2(lcc aa,lcc bb){return aa.id<bb.id;}
int main(){
scanf("%d%d",&n,&m);
int x,y,z;
for(int i=;i<n;i++){
scanf("%d",&y);
init(y+,i+);
fa[i+]=y+;
}tot=;dfs1();dfs2(,);build(,,n);tot=;
for(int j=;j<=m;j++){
scanf("%d%d%d",&x,&y,&z);
x++;y++;z++;
if(y<x)swap(x,y);
q[++tot].num=x-;q[tot].z=z;q[tot].id=tot;
q[++tot].num=y;q[tot].z=z;q[tot].id=tot;
}sort(q+,q++tot,cmp1);
int now=;
for(int i=;i<=tot;i++){
while(now<q[i].num){
now++;datup(now);
}
q[i].ans=doit(q[i].z);
}
sort(q+,q++tot,cmp2);
for(int i=;i<=m;i++){
long long z=(q[i*].ans-q[i*-].ans)%;
printf("%lld\n",z);
}
return ;
}

BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线的更多相关文章

  1. 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

  2. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  3. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  4. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  5. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  6. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  7. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  8. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  9. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  10. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

随机推荐

  1. 【BZOJ】1251: 序列终结者

    [题意]给定含有n个0的的数列. 1.区间加值 2.区间翻转 3.区间求最大值 [算法]平衡树(fhq-treap) 需要特别注意的是: 1.使0点对全局无影响并全程保持(例如求max,t[0].mx ...

  2. 【洛谷 P4542】 [ZJOI2011]营救皮卡丘(费用流)

    题目链接 用最多经过\(k\)条经过\(0\)的路径覆盖所有点. 定义\(ds[i][j]\)表示从\(i\)到\(j\)不经过大于\(max(i,j)\)的点的最短路,显然可以用弗洛伊德求. 然后每 ...

  3. HDU 5995 Kblack loves flag (模拟)

    题目链接 Problem Description Kblack loves flags, so he has infinite flags in his pocket. One day, Kblack ...

  4. 如何写出优雅的js以及js特殊技巧

    由于代码和解释都写在了github的readme内部,这里就直接附上github:https://github.com/jiangzhenfei/pretty-js/tree/master

  5. 关于angularJS的一些用法

    AngularJS 事件指令: ng-click/dblclick ng-mousedown/up ng-mouseenter/leave ng-mousemove/over/out ng-keydo ...

  6. linux编程之main()函数启动过程【转】

    转自:http://blog.csdn.net/gary_ygl/article/details/8506007 1 最简单的程序  1)编辑helloworld程序,$vim helloworld. ...

  7. 牛B的日本精神

    在汤森路透评选出的<2015全球创新企业百强>榜单里,日本以40家高居榜首,力压美国的35家.而中国内地无一入围.   在中国媒体上,我们见到的日本是“失去的20年”,经济衰退.创新能力丧 ...

  8. photoshop 安装问题

    问题:“安装程序检测到计算机重新启动操作可能处于挂起状态.建议您退出安装程序,重新启动并重试.” 解决: 1.运行 regedit 打开注册表编辑器. 2.依次展开HKEY_LOCAL_MACHINE ...

  9. Deep Learning基础--Softmax求导过程

    一.softmax函数 softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类! 假设我们有一个数组,V,Vi表示V中的第i个元素,那么这个 ...

  10. 2017 SWERC

    2017 SWERC A:Cakey McCakeFace 题目描述:有一个炉每次只能放一个蛋糕,炉的进口和出口各放了一个探测器,当放蛋糕进去时,进口的探测器会记录时刻,当蛋糕做好后,蛋糕从出口出来, ...