显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 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<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const long long N=;
const long long mod=;
long long cnt,head[N];
long long size[N],fa[N],dep[N],son[N];
long long top[N],id[N],tot;
long long n,m,lm[N],rm[N];
struct que{
long long l,r,z;
}q[N];
struct tree{
long long l,r,sum,lazy;
}tr[N*];
vector<long long> l[N],r[N];
struct edge{
long long to,nxt;
}e[N*];
void add(long long u,long long v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs1(long long u,long long f,long long deep){
size[u]=;
fa[u]=f;
dep[u]=deep;
long long maxson=-;
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].to;
if(v==f)continue;
dfs1(v,u,deep+);
size[u]+=size[v];
if(size[v]>maxson){
maxson=size[v];
son[u]=v;
}
}
}
void dfs2(long long u,long long tp){
top[u]=tp;
id[u]=++tot;
if(!son[u])return;
dfs2(son[u],tp);
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].to;
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
void build(long long l,long long r,long long now){
tr[now].l=l;tr[now].r=r;
if(l==r)return;
long long mid=(l+r)>>;
build(l,mid,now*);
build(mid+,r,now*+);
}
void update(long long now){
tr[now].sum=tr[now*].sum+tr[now*+].sum;
tr[now].sum%=mod;
}
void pushdown(long long now){
if(tr[now].lazy==)return;
tr[now*].sum+=((tr[now*].r-tr[now*].l+)*tr[now].lazy)%mod;
tr[now*].sum%=mod;
tr[now*+].sum+=((tr[now*+].r-tr[now*+].l+)*tr[now].lazy)%mod;
tr[now*+].sum%=mod;
tr[now*].lazy+=tr[now].lazy;
tr[now*].lazy%=mod;
tr[now*+].lazy+=tr[now].lazy;
tr[now*+].lazy%=mod;
tr[now].lazy=;
}
void change(long long l,long long r,long long now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
tr[now].sum+=(tr[now].r-tr[now].l+)%mod;
tr[now].sum%=mod;
tr[now].lazy+=;
return;
}
long long mid=(tr[now].l+tr[now].r)>>;
if(l>mid)change(l,r,now*+);
else if(r<=mid)change(l,r,now*);
else{
change(l,mid,now*);
change(mid+,r,now*+);
}
update(now);
}
long long getsum(long long l,long long r,long long now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
return tr[now].sum;
}
long long mid=(tr[now].l+tr[now].r)>>;
if(l>mid)return getsum(l,r,now*+);
else if(r<=mid)return getsum(l,r,now*);
else {
return (getsum(l,mid,now*)+getsum(mid+,r,now*+))%mod;
}
}
void changel(long long x,long long y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
change(id[top[x]],id[x],);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
change(id[x],id[y],);
}
long long getsuml(long long x,long long y){
long long ans=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=getsum(id[top[x]],id[x],);
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
ans+=getsum(id[x],id[y],);
ans%=mod;
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(long long i=;i<=n;i++){
long long u;
scanf("%lld",&u);
add(u+,i);add(i,u+);
}
dfs1(,,);
dfs2(,);
build(,n,);
for(long long i=;i<=m;i++){
scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].z);
q[i].l++;q[i].r++;q[i].z++;
l[q[i].l-].push_back(i);
r[q[i].r].push_back(i);
}
for(long long i=;i<=n;i++){
changel(i,);
for(long long j=;j<l[i].size();j++){
lm[l[i][j]]=getsuml(q[l[i][j]].z,);
}
for(long long j=;j<r[i].size();j++){
rm[r[i][j]]=getsuml(q[r[i][j]].z,);
}
}
for(long long i=;i<=m;i++){
printf("%lld\n",(rm[i]-lm[i]+mod)%mod);
}
return ;
}

BZOJ 3626 LCA(离线+树链剖分+差分)的更多相关文章

  1. BZOJ 3626 LCA(离线+树链剖分)

    首先注意到这样一个事实. 树上两个点(u,v)的LCA的深度,可以转化为先将u到根路径点权都加1,然后求v到根路径上的总点权值. 并且该题支持离线.那么我们可以把一个区间询问拆成两个前缀和形式的询问. ...

  2. bzoj 3626: [LNOI2014]LCA 离线+树链剖分

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

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

    题面 考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\). 显然这些LCA一定在\(z\)到根的路径上.下面的问题就是怎么统计. 考虑不是那么暴力的暴 ...

  4. 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树

    [BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...

  5. 【BZOJ3626】LCA(树链剖分,Link-Cut Tree)

    [BZOJ3626]LCA(树链剖分,Link-Cut Tree) 题面 Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. ...

  6. BZOJ 3626 离线+树链剖分+线段树

    思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...

  7. 【树链剖分 差分】bzoj3626: [LNOI2014]LCA

    把LCA深度转化的那一步还是挺妙的.之后就是差分加大力数据结构了. Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep ...

  8. JZYZOJ1454 NOIP2015 D2T3_运输计划 二分 差分数组 lca tarjan 树链剖分

    http://172.20.6.3/Problem_Show.asp?id=1454 从这道题我充分认识到我的脑子里好多水orz. 如果知道了这个要用二分和差分写,就没什么思考上的难点了(屁咧你写了一 ...

  9. BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...

随机推荐

  1. 计算label

    func getCGSize(size:CGSize,fontSize:CGFloat,text:String)->CGSize{ let attributes = [NSFontAttribu ...

  2. centos下nginx配置

    转自  http://www.linuxidc.com/Linux/2016-09/134907.htm 安装所需环境 Nginx 是 C语言 开发,建议在 Linux 上运行,当然,也可以安装 Wi ...

  3. swift语言点评十六-Initialization && Deinitialization

    initial value:必须初始化.不影响观察者 Classes and structures must set all of their stored properties to an appr ...

  4. 解析浏览器和nodejs环境下console.log()的区别

    写在前面的 在开发调试过程中,我们经常需要调用console.log 方法来打印出当前变量的值,然而,console.log在浏览器环境下 有时会出现一些异常的现象 开撸代码 在浏览器和nodejs环 ...

  5. 中级前端工程师要掌握的JavaScript 技巧

    1.判断对象的数据类型 2.Es5实现数组map方法 3.使用reduce实现数组map方法 4.ES5 实现数组filter方法 5.使用reduce实现filter方法 6.ES5 实现数组som ...

  6. 虚拟机创建后该如何获取IP地址并访问互联网实用教程

    之前在做项目的时候主机IP地址.网关.DNS.子网掩码等都是公司或者对方直接给提供的,但是如果我们自己想搭建一台虚拟机或者一台集群的话,手头又没有IP地址,该肿么办呢?   白慌,这里介绍一个小技巧, ...

  7. sz xshell

    yum install lrzsz -y

  8. ProGuard常见问题及解决套路

    ProGuard是一个压缩.优化和混淆Java字节码的工具,非常好用.本篇文章总结一下许多人在使用ProGuard时经常遇到的问题. 我把在使用ProGuard时经常遇到的问题分为两类,分别是导致构建 ...

  9. 对jvm进行gc的时间、数量、jvm停顿时间的监控

    在jdk中一个类可以获得gc的信息: public static void main(String[] args) { List<GarbageCollectorMXBean> garba ...

  10. mysql中文乱码解决方式

    近期项目使用到mysql.却突然出现了中文乱码问题.尝试了多种方案,最终解决乱码问题,总结一下解决方式,给遇到同样问题的人一点參考. 中文乱码的原因 1.安装mysqlserver的时候编码集设定有问 ...