BZOJ 3626 LCA(离线+树链剖分+差分)
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 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(离线+树链剖分+差分)的更多相关文章
- BZOJ 3626 LCA(离线+树链剖分)
首先注意到这样一个事实. 树上两个点(u,v)的LCA的深度,可以转化为先将u到根路径点权都加1,然后求v到根路径上的总点权值. 并且该题支持离线.那么我们可以把一个区间询问拆成两个前缀和形式的询问. ...
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
- [BZOJ3626] [LNOI2014] LCA 离线 树链剖分
题面 考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\). 显然这些LCA一定在\(z\)到根的路径上.下面的问题就是怎么统计. 考虑不是那么暴力的暴 ...
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
[BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...
- 【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
[BZOJ3626]LCA(树链剖分,Link-Cut Tree) 题面 Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. ...
- BZOJ 3626 离线+树链剖分+线段树
思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...
- 【树链剖分 差分】bzoj3626: [LNOI2014]LCA
把LCA深度转化的那一步还是挺妙的.之后就是差分加大力数据结构了. Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep ...
- JZYZOJ1454 NOIP2015 D2T3_运输计划 二分 差分数组 lca tarjan 树链剖分
http://172.20.6.3/Problem_Show.asp?id=1454 从这道题我充分认识到我的脑子里好多水orz. 如果知道了这个要用二分和差分写,就没什么思考上的难点了(屁咧你写了一 ...
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
随机推荐
- xBIM 高级01 IFC多模型合并
系列目录 [已更新最新开发文章,点击查看详细] 多模型合并可以实现以下功能: 覆盖多个模型以表现得像一个模型 统一访问数据,就像它是单个模型一样 只读.要修改模型的内容,您必须使用特定模型 不 ...
- 你不知道的JavaScript(七)delete操作符
JS中的delete操作符不是太常用,容易被忽略,它的作用很简单,用来删除对象的属性或方法. <script type="text/javascript"> var p ...
- fastdfs+nginx的安装部署
原理图: fastdfs适用场景: fastdfs特别适合海量 中小文件(建议范围:4KB< file_size <500MB)为载体的在线服务. 安装系统介绍: CentOS6.6 安装 ...
- BZOJ 4199: [Noi2015]品酒大会 后缀自动机_逆序更新
一道裸题,可以考虑自底向上去更新方案数与最大值. 没啥难的 细节........ Code: #include <cstdio> #include <algorithm> #i ...
- layer弹窗
layer.alert(content, options, yes) - 普通信息框 它的弹出似乎显得有些高调,一般用于对用户造成比较强烈的关注,类似系统alert,但却比alert更灵便.它的参数是 ...
- NOIp2018模拟赛三十八
爆〇啦~ A题C题不会写,B题头铁写正解: 随手过拍很自信,出分一看挂成零. 若要问我为什么?gtmdsubtask! 神tm就一个subtask要么0分要么100,结果我预处理少了一点当场去世 难受 ...
- POJ 1821 Fence(单调队列优化DP)
题解 以前做过很多单调队列优化DP的题. 这个题有一点不同是对于有的状态可以转移,有的状态不能转移. 然后一堆边界和注意点.导致写起来就很难受. 然后状态也比较难定义. dp[i][j]代表前i个人涂 ...
- C语言运行时数据结构
段(Segment): 对象文件/可执行文件: SVr4 UNIX上被称为ELF(起初"Extensible Linker Format", 现在"Executable ...
- Java基础学习总结(4)——对象转型
一.对象转型介绍 对象转型分为两种:一种叫向上转型(父类对象的引用或者叫基类对象的引用指向子类对象,这就是向上转型),另一种叫向下转型.转型的意思是:如把float类型转成int类型,把double类 ...
- C++的hashmap和Java的hashmap
C++里面是这样的:typedef std::unordered_map<std::string,std::string> stringmap; std::unordered_map< ...