Description

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设$dep[i]$表示点i的深度,$lca(i,j)$表示i与j的最近公共祖先。
有q次询问,每次询问给出l,r,z,求$\sum\limits_{i=l}^{r}dep[lca(i,z)]$。
(即求在$[l,r]$区间内的每个节点i与z的最近公共祖先的深度之和)

$n,q<=50000$

Input

第一行2个整数n,q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l,r,z。

Output

输出q行,每行表示一个询问的答案。每个答案对201314取模输出

Sample Input

5 2
0
0
1
1
1 4 3
1 4 2

Sample Output

8
5

这题不算很难,但是看到正解的方法很有趣,就记录一下~

考虑暴力,每次询问把z到根的所有节点打上标记,枚举i的时候直接往根找第一个有标记的点,然后统计深度即可。

然而复杂度明显是大于$O(n^2q)$的,显然不能接受,容易发现如果把深度看成点权,那么统计深度就相当于把z到根的每个节点权值都加一,然后枚举时统计根节点到i的权值和。使用树链剖分可以降到$O(nqlog^2n)$,但是还是会超时。

考虑进一步优化,发现询问可以差分,拆成$[1,l-1]$和$[1,r]$两个询问,进一步可以发现对答案有贡献的点只会在$lca(i,z)$以上,因此把每个i到根路径上的结点权值加一,再统计z到根节点的权值和,得出的答案是相同的。再结合差分,每次直接将$[1,l-1]$或$[1,r]$中所有节点到根节点路径上的点权值加一,然后统计z到根节点的权值和,按照dfs序区间修改+区间查询,用树链剖分加线段树可以做到$O(qlog^2n)$,用LCT可以做到$O(qlogn)$

注意long long

代码:

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define mod 201314
using namespace std;
typedef long long ll;
struct edge{
int v,next;
}a[];
struct task{
int r,z,id,ok;
}q[];
int n,qq,u,v,z,tmp=,qqq=,tot=,tim=,head[],son[],siz[],fa[],dep[],dfn[],top[];
ll t[],laz[],tv[],ans[],anss;
bool cmp(task a,task b){
return a.r<b.r;
}
void add(int u,int v){
a[++tot].v=v;
a[tot].next=head[u];
head[u]=tot;
}
void dfs1(int u,int f,int dpt){
dep[u]=dpt;
fa[u]=f;
siz[u]=;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(!dep[v]){
dfs1(v,u,dpt+);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]||son[u]==-)son[u]=v;
}
}
}
void dfs2(int u,int tp){
dfn[u]=++tim;
top[u]=tp;
if(son[u]!=-)dfs2(son[u],tp);
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(v!=son[u])dfs2(v,v);
}
}
void pushup(int u){
t[u]=t[u*]+t[u*+];
}
void pushdown(int u){
if(laz[u]){
laz[u*]+=laz[u];
laz[u*+]+=laz[u];
t[u*]+=tv[u*]*laz[u];
t[u*+]+=tv[u*+]*laz[u];
laz[u]=;
}
}
void build(int l,int r,int u){
if(l==r){
tv[u]=;
return;
}
int mid=(l+r)/;
build(l,mid,u*);
build(mid+,r,u*+);
tv[u]=tv[u*]+tv[u*+];
}
void updata(int l,int r,int u,int L,int R,int v){
if(L<=l&&r<=R){
t[u]+=(ll)tv[u]*v;
laz[u]+=v;
return;
}
int mid=(l+r)/;
pushdown(u);
if(L<=mid)updata(l,mid,u*,L,R,v);
if(mid<R)updata(mid+,r,u*+,L,R,v);
pushup(u);
}
ll query(int l,int r,int u,int L,int R){
if(L<=l&&r<=R){
return t[u];
}
int mid=(l+r)/,ans=;
pushdown(u);
if(L<=mid)ans+=query(l,mid,u*,L,R);
if(R>mid)ans+=query(mid+,r,u*+,L,R);
return ans;
}
void work(int u){
while(u){
int v=top[u];
updata(,n,,dfn[v],dfn[u],);
u=fa[v];
}
}
ll _work(int u){
ll ans=;
while(u){
int v=top[u];
ans+=query(,n,,dfn[v],dfn[u]);
u=fa[v];
}
return ans;
}
int main(){
memset(son,-,sizeof(son));
memset(head,-,sizeof(head));
scanf("%d%d",&n,&qq);
for(int i=;i<n;i++){
scanf("%d",&u);
add(u+,i+);
}
dfs1(,,);
dfs2(,);
build(,n,);
for(int i=;i<=qq;i++){
scanf("%d%d%d",&u,&v,&z);
u++,v++,z++;
q[++qqq]=(task){u-,z,i,-};
q[++qqq]=(task){v,z,i,};
}
sort(q+,q+qqq+,cmp);
for(int i=;i<=qqq;i++){
while(tmp<q[i].r){
work(++tmp);
}
ans[q[i].id]+=(ll)q[i].ok*_work(q[i].z);
}
for(int i=;i<=qq;i++){
printf("%lld\n",ans[i]%mod);
}
return ;
}

【LNOI2014】【BZOJ3626】NOIp2018模拟(三) LCA的更多相关文章

  1. [NOIP2018模拟赛10.16]手残报告

    [NOIP2018模拟赛10.16]手残报告 闲扯 炉石乱斗模式美滋滋啊,又颓到好晚... 上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了 ...

  2. JZOJ5883【NOIP2018模拟A组9.25】到不了——动态LCA裸题

    题目描述 Description wy 和 wjk 是好朋友. 今天他们在一起聊天,突然聊到了以前一起唱过的<到不了>. "说到到不了,我给你讲一个故事吧." &quo ...

  3. NOIp2018模拟赛三十六

    好久没打模拟赛了...今天一样是两道国集,一道bzoj题 成绩:13+0+95=108 A题开始看错题了...导致样例都没看懂,结果xfz提醒我后我理解了一个我自认为正确的题意(事实证明我和xfz都错 ...

  4. EZ 2018 03 09 NOIP2018 模拟赛(三)

    最近挺久没写比赛类的blog了 链接:http://211.140.156.254:2333/contest/59 这次的题目主要考验的是爆搜+打表的能力 其实如果你上来就把所有题目都看过一次就可以知 ...

  5. NOIp2018模拟赛三十八

    爆〇啦~ A题C题不会写,B题头铁写正解: 随手过拍很自信,出分一看挂成零. 若要问我为什么?gtmdsubtask! 神tm就一个subtask要么0分要么100,结果我预处理少了一点当场去世 难受 ...

  6. NOIp2018模拟赛三十七

    奇怪的一场... 前两题都是全场题,C题明显不可做,我题目都没看懂...(STO lhx OTZ) 成绩:100+100+8=208 貌似十几个208的...A题暴力$O(nmc)$能过...暴力容斥 ...

  7. NOIp2018模拟赛三十五

    两道大数据结构把我砸懵 成绩:未提交 Orz xfz两道正解 A:[BZOJ4049][CREC2014B]mountainous landscape B:CJB的大作(CF改编题)

  8. NOIp2018模拟赛三十三

    神奇的一场... 成绩:100+0+14=114 A题是个体面很恐怖的题...然而看懂题意之后转化一下就变成了一道暴力傻逼题...但是不知道为什么dalao们都没写,讲题的时候挺尴尬的...yrx“瞄 ...

  9. NOIp2018模拟赛三十二

    继续挂成傻逼 成绩:100+0+10(90)=110 A全场一眼题,C没取模挂八十分,然后没特判特殊情况又挂十分 A:[agc009b]tournament(太简单,咕了) B:[ATC2142]Bu ...

随机推荐

  1. Image解码

    Image解码 可以看到从CFDataRef直到创建出UIImage,都没有调用过对图像解码的函数,只读取了一些图像基础数据和元数据. Image解码发生在什么时候?在ImageIO/CGImageS ...

  2. Pyhton学习——Day8

    ###########################################max函数#################################################### ...

  3. C#追加、拷贝、删除、移动文件、创建目录、递归删除文件夹及文件

    C#追加文件 StreamWriter sw = File.AppendText(Server.MapPath(".")+"\\myText.txt"); sw ...

  4. BeanUtils(前端赋值给后台,忽略空属性)

    package com.drn.core.util; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; im ...

  5. vue路由传值params和query的区别

    vue路由传值params和query的区别1.query传参和接收参数传参: this.$router.push({ path:'/xxx' query:{ id:id } })接收参数: this ...

  6. UVALive 5545 Glass Beads

    Glass Beads Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Origin ...

  7. Run Nutch In Eclipse on Linux and Windows nutch version 0.9

    Running Nutch in Eclipse Here are instructions for setting up a development environment for Nutch un ...

  8. ASP.NET-model验证

    在ASP.NET的model中,可以定义下面的这种属性,来实现前台签证字符串 RegularExpression(@"(|.*(?=.{6,})(?=.*\d)(?=.*[a-zA-Z]). ...

  9. COGS——T 2739. 凯伦和咖啡

    http://www.cogs.pro/cogs/problem/problem.php?pid=2739 ★★☆   输入文件:coffee.in   输出文件:coffee.out   简单对比时 ...

  10. Spring中基于Java的配置@Configuration和@Bean用法 (转)

    spring中为了减少xml中配置,可以生命一个配置类(例如SpringConfig)来对bean进行配置. 一.首先,需要xml中进行少量的配置来启动Java配置: <?xml version ...