题目: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 ;
}

最新文章

  1. 《精通Hibernate:Java对象持久化技术详解》目录
  2. int与string之间的类型转换--示例
  3. php 单引号 双引号 ,php字符串/ hmtl / 数据库显示/ 及php的几个转化函数
  4. 1043. Is It a Binary Search Tree
  5. EF如何正确的进行实体中修改
  6. Inspiron 14 7000 系列 (7447) 游匣14 拆机图
  7. 【Linux】鸟哥的Linux私房菜基础学习篇整理(十一)
  8. Delphi XE7中新并行库
  9. jquery取出所有包含class=&#39;engineer_val&#39;的值
  10. Largest Rectangle in a Histogram [POJ2559] [单调栈]
  11. docker备份mongodb数据,导入导出
  12. pagehelper 使用
  13. webStrom访问只一个很简单的html文件的时候显示local host无法访问。。
  14. 使用Nexus2搭建Maven本地仓库
  15. mfc editline 变为大框框
  16. Mac 下安装.NET Core 与 CLI
  17. MySQL中EXPLAIN解释命令 查看索引是否生效
  18. App开发准备
  19. 【星云测试】开发者测试(3)-采用精准测试工具对springcloud微服务应用进行穿透测试
  20. 教你Snapseed软件八个常用调图工具

热门文章

  1. android去除标题栏和状态栏(全屏)
  2. C#路径,文件,目录,I/O常见操作汇总
  3. js编程习惯
  4. msp430入门编程30
  5. js面试题总结
  6. java 字节码 指令集
  7. ArcGIS中Shapefile和Geodatabase坐标容差的问题
  8. linux动态库的种种要点
  9. POJ 1988 Cube Stacking(并查集+路径压缩)
  10. linux下weblogic11g成功安装后,启动报错Getting boot identity from user