思路转化很巧妙。

首先把询问做差分。

然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和。

这样和原问题是等价的,然后树链剖分+线段树就可以做了。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define md 201314
#define maxn 100005 int n,q,dep[maxn],data[maxn],ans[maxn]; namespace SegTree{
int sum[maxn<<3],dsum[maxn<<3],tag[maxn<<3];
void update(int o)
{
sum[o]=(sum[o<<1]+sum[o<<1|1])%md;
}
void build(int o,int l,int r)
{
if (l==r)
{
sum[o]=tag[o]=0;
return ;
}
int mid=l+r>>1;
build(o<<1,l,mid); build(o<<1|1,mid+1,r);
update(o);
}
void pushdown(int o,int l,int r)
{
if (tag[o]!=0)
{
int mid=l+r>>1;
tag[o<<1]+=tag[o];tag[o<<1|1]+=tag[o];
sum[o<<1]+=tag[o]*(mid-l+1);
sum[o<<1|1]+=tag[o]*(r-mid);
tag[o]=0;
}
}
int querysum(int o,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return sum[o];
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return querysum(o<<1,l,mid,L,R);
else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R);
else return (querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R))%md;
}
void modify(int o,int l,int r,int L,int R,int f)
{
if (L<=l&&r<=R)
{
sum[o]+=(r-l+1)*f;
tag[o]+=f;
return ;
}
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o);
else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o);
else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o);
}
} namespace Tree{
int h[maxn],to[maxn],ne[maxn],en=0;
int siz[maxn],son[maxn],dfn[maxn],top[maxn],fa[maxn],tot;
int pos[maxn],id[maxn];
vector < pair<int,int> > v[maxn];
void add(int a,int b)
{
to[en]=b;ne[en]=h[a];h[a]=en++;
}
void dfs1(int o)
{
siz[o]=1;
for (int i=h[o];i>=0;i=ne[i])
{
dep[to[i]]=dep[o]+1;
fa[to[i]]=o;
dfs1(to[i]);
siz[o]+=siz[to[i]];
if (siz[to[i]]>siz[son[o]]) son[o]=to[i];
}
}
void dfs2(int o,int tp)
{
top[o]=tp;pos[o]=++tot;id[tot]=o;
if (!son[o]) return;
dfs2(son[o],tp);
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=son[o]) dfs2(to[i],to[i]);
return ;
}
void build()
{
F(i,1,n) data[i]=dep[id[i]];
SegTree::build(1,1,n);
}
void add(int a,int b,int f)
{
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
SegTree::modify(1,1,n,pos[top[a]],pos[a],f);
a=fa[top[a]];
}
if (dep[a]<dep[b]) swap(a,b);
SegTree::modify(1,1,n,pos[b],pos[a],f);
}
int query(int a,int b)
{
int ret=0;
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ret+=SegTree::querysum(1,1,n,pos[top[a]],pos[a]);
ret%=md;
a=fa[top[a]];
}
if (dep[a]<dep[b]) swap(a,b);
ret+=SegTree::querysum(1,1,n,pos[b],pos[a]);
return ret%md;
}
void work()
{
F(i,1,q)
{
int l,r,z; scanf("%d%d%d",&l,&r,&z);l++;r++;z++;
v[l-1].push_back(mp(z,-i));
v[r].push_back(mp(z,i));
}
F(i,1,n)
{
add(1,i,1);
for (int j=0;j<v[i].size();++j)
{
pair<int,int> pa=v[i][j];
if (pa.second<0) ans[-pa.second]-=query(1,pa.first);
else ans[pa.second]+=query(1,pa.first);
}
}
F(i,1,q) printf("%d\n",(ans[i]+md)%md);
}
} namespace Graph{
int h[maxn],to[maxn],ne[maxn],en=0;
void add(int a,int b)
{to[en]=b;ne[en]=h[a];h[a]=en++;}
void dfs(int o,int fa)
{
if (fa) Tree::add(fa,o);
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=fa) dfs(to[i],o);
}
} int main()
{
scanf("%d%d",&n,&q);
memset(Tree::h,-1,sizeof Tree::h);
memset(Graph::h,-1,sizeof Graph::h);
F(i,2,n)
{
int fa; scanf("%d",&fa);
Graph::add(fa+1,i);
}
Graph::dfs(1,0);
dep[1]=1;
Tree::dfs1(1);
Tree::dfs2(1,1);
Tree::build();
Tree::work();
}

  

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. bzoj3626 [LNOI2014]LCA——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 思路很巧妙,把区间换成前缀和相减: 把 l ~ r 到根路径上的点的点权都+1,然后 ...

  9. [LNOI2014]LCA(树链剖分)

    BZOJ传送门 Luogu传送门 题目:给你一棵树,给你n个询问,每个询问要求输出$\sum_{i=l}^{r}depth(LCA(i,z))$ 细看看其实没有想象的那么难 大体思路: 1.对于每个询 ...

随机推荐

  1. Codeforces Round #313 (Div. 2) A.B,C,D,E Currency System in Geraldion Gerald is into Art Gerald's Hexagon Equivalent Strings

    A题,超级大水题,根据有没有1输出-1和1就行了.我沙茶,把%d写成了%n. B题,也水,两个矩形的长和宽分别加一下,剩下的两个取大的那个,看看是否框得下. C题,其实也很简单,题目保证了小三角形是正 ...

  2. ubuntu 18.04下 配置qt opencv的坑

    问题和过程描述: 我按照网上的教程装了qt5.8版本,然后去配置opencv,感觉一切顺利,然后随便写了个 Mat src = imread("xxx") 然后imshow发现编译 ...

  3. 剑指offer46 求1+2+...+n 以及& &&区别

    参考代码: class Solution { public: int Sum_Solution(int n) { int result = n; result && (result + ...

  4. spring5之SAXParseException:cvc-elt.1: 找不到元素 “beans” 的声明

    之前SSM项目一直报错,就是找不到错误  气啊 后来在网上找到了答案:燕来spring5之后就不再需要写版本号了

  5. 【Python全栈-JavaScript】JavaScript-字符串详解

    JavaScript-字符串详解 预热:Number() 方法 <script> //重要等级 1,2,3,4,5 var s=10; //最高级别5 var s1=new Number( ...

  6. 安装IAR ewarm

    一  安装准备 (ST方案) 1 嵌入式集成开发环境IAR ewarm 5.41 2 J-Link4.20 3 emberznet-4.3.0协议栈安装包 option1:tools - stm32软 ...

  7. iOS中的数据存储方式_Preference(NSUserDefaults)

    NSUserDefaults适合存储轻量级的本地数据,项目中,我会把一些简单的数据密码.网址.登陆状态BOOL.整型/浮点型数据等和用户有关的数据用它存储.但是它不能存储自定义的对象! 实例化一个 N ...

  8. odoo10 api 装饰器

    http://www.cnblogs.com/kfx2007/p/3894297.html one:装饰record-style方法中的self为单一实例,被装饰的方法将会在每一条记录中循环调用,返回 ...

  9. git使用stash存储相关操作

    git stash  将当前修改存储起来 git stash apply 恢复最近一次存储 git stash apply stash@{2} 恢复某一次存储 git stash list 查看存储列 ...

  10. 《鸟哥的Linux私房菜》学习笔记(1)——文件与目录

    在Linux中,任何设备都是文件,不仅如此,连数据通信的接口也有专门的文件负责.可以说,一切皆文件,目录也是一种文件,是路径映射.因此,文件系统是Linux的基础. 一.文件与目录管理命令 1.ls( ...