题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626

思路很巧妙,把区间换成前缀和相减;

把 l ~ r 到根路径上的点的点权都+1,然后 z 到根求和,就是 z 与 l  ~ r 每个点 lca 深度的和;

这里若要用前缀和,则需要把询问离线排序;

然后上树链剖分,修改和求和线段树解决即可。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=,mod=;
int n,m,fa[maxn],head[maxn],ct,dfn[maxn],tim;
int top[maxn],to[maxn],siz[maxn],tl[maxn],tr[maxn];
struct N{
int to,next;
N(int t=,int n=):to(t),next(n) {}
}edge[maxn<<];
struct T{ll s,lzy,size;}t[maxn<<];
struct Q{int l,r,z,bh;ll ansl,ansr;}q[maxn];
void add(int x,int y){edge[++ct]=N(y,head[x]);head[x]=ct;}
bool cmp(int x,int y){return q[x].l<q[y].l;}
bool cmp2(int x,int y){return q[x].r<q[y].r;}
int rd()
{
int ret=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return ret;
}
void dfs(int x,int f)
{
siz[x]=;
for(int i=head[x];i;i=edge[i].next)
{
int u=edge[i].to;
if(u==f)continue;
dfs(u,x); siz[x]+=siz[u];
if(siz[u]>siz[to[x]])to[x]=u;
}
}
void dfs2(int x)
{
dfn[x]=++tim;
if(to[x])top[to[x]]=top[x],dfs2(to[x]);
for(int i=head[x];i;i=edge[i].next)
{
int u=edge[i].to;
if(u==fa[x]||u==to[x])continue;
top[u]=u; //top[u]!=x !!!
dfs2(u);
}
}
void pushup(int x)
{
t[x].size=t[x<<].size+t[x<<|].size;
t[x].s=t[x<<].s+t[x<<|].s;
}
void pushdown(int x)
{
if(!t[x].lzy)return;
int ls=(x<<),rs=(x<<|);
ll l=t[x].lzy;t[x].lzy=;
t[ls].s+=l*t[ls].size; t[ls].lzy+=l;
t[rs].s+=l*t[rs].size; t[rs].lzy+=l;
}
void build(int x,int l,int r)
{
if(l==r){t[x].size=; return;}
int mid=((l+r)>>);
build(x<<,l,mid); build(x<<|,mid+,r);
pushup(x);
}
void update(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)
{
t[x].s+=t[x].size; t[x].lzy++;
return;
}
pushdown(x);
int mid=((l+r)>>);
if(mid>=L)update(x<<,l,mid,L,R);
if(mid<R)update(x<<|,mid+,r,L,R);
pushup(x);
}
void work(int x)//x 到 rt 路径上点权+1
{
while(x)
{
update(,,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
// update(1,1,n,dfn[rt],dfn[rt]);
}
ll query(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)return t[x].s;
int mid=((l+r)>>); ll ret=;
pushdown(x);
if(mid>=L)ret+=query(x<<,l,mid,L,R);
if(mid<R)ret+=query(x<<|,mid+,r,L,R);
return ret;
}
ll qry(int x)
{
ll ret=;
while(x)
{
ret+=query(,,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
return ret;
}
int main()
{
n=rd();m=rd();
for(int i=;i<=n;i++){fa[i]=rd()+; add(fa[i],i); add(i,fa[i]);}
for(int i=;i<=m;i++)
{
q[i].l=rd()+; q[i].r=rd()+; q[i].z=rd()+;
tl[i]=i; tr[i]=i;
}
sort(tl+,tl+m+,cmp);
sort(tr+,tr+m+,cmp2);
dfs(,); top[]=; dfs2(); build(,,n);
int dl=,dr=;
while(q[tl[dl]].l==)dl++;
for(int i=;i<=n;i++)
{
work(i);
while(q[tl[dl]].l-==i&&dl<=m)
{
q[tl[dl]].ansl=qry(q[tl[dl]].z);//不套 dfn !!!
dl++;
}
while(q[tr[dr]].r==i&&dr<=m)
{
q[tr[dr]].ansr=qry(q[tr[dr]].z);
dr++;
}
}
for(int i=;i<=m;i++)
printf("%lld\n",(q[i].ansr-q[i].ansl)%mod);
return ;
}

bzoj3626 [LNOI2014]LCA——树链剖分的更多相关文章

  1. [BZOJ3626] [LNOI2014]LCA(树链剖分)

    [BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...

  2. BZOJ3626[LNOI2014]LCA——树链剖分+线段树

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

  3. BZOJ3626 [LNOI2014]LCA 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3626 题意概括 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节 ...

  4. bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)

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

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

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

  6. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  7. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  8. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

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

  9. BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

    http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...

随机推荐

  1. [HNOI2009]梦幻布丁(链表+启发式合并)

    洛谷传送门 开始一个O(n^2)思路,每次每句要改变颜色的点,改变完颜色后重新计算颜色的段数,显然拉闸. 然后呢..然后就不会了. 看了别人博客,才知道有个叫做启发式合并的东西,就是把小的合并到大的上 ...

  2. hdu 3371

    #include<stdio.h> #include<stdlib.h> #define N 501 struct node { int x,y,dis; }road[N*N] ...

  3. Codevs 3556 科技庄园==洛谷 P2760

    时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题目描述 Description Life是codevs的用户,他是一个道德极高的用户,他积极贯彻党的十八大精神, ...

  4. BZOJ2501: [usaco2010 Oct]Soda Machine

    n<=50000个区间,求哪个点被覆盖区间数量最多,输出这个数量. 差分模板..然而数组忘开两倍.. #include<stdio.h> #include<string.h&g ...

  5. 微软2016校园招聘在线笔试 B Professor Q's Software [ 拓扑图dp ]

    传送门 题目2 : Professor Q's Software 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Professor Q develops a new s ...

  6. 前端学习之- Ajax

    Ajax:页面不做刷新,直接将数据悄悄提交到后台,然后通过回调函数处理返回结果. $.Ajax({ # 提交到后台 url:'/host', # 提交到哪里 type:'POST' # 提交方式 da ...

  7. 编译.net .net Core程序 代码,仅做备份

    //创建一个ProcessStartInfo对象 使用系统shell 指定命令和参数 设置标准输出 //编译.net core项目 var psi = new ProcessStartInfo(&qu ...

  8. 七天从零基础学习android(1)--配置环境

    在写这篇文的时候android开发经验还是0,是一个萌新,这是一篇记录一个萌新从零android编程基础到能编写一个记账本的开发过程(至少我是这样美好的希望着的) 首先因为是没有开发基础的,直接上百度 ...

  9. 30分钟学会如何使用Shiro(转)

    本文转自http://www.cnblogs.com/learnhow/p/5694876.html 感谢作者 本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jin ...

  10. HDU 4279 Number(找规律)

    Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...