【LNOI2014】【BZOJ3626】NOIp2018模拟(三) LCA
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的更多相关文章
- [NOIP2018模拟赛10.16]手残报告
[NOIP2018模拟赛10.16]手残报告 闲扯 炉石乱斗模式美滋滋啊,又颓到好晚... 上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了 ...
- JZOJ5883【NOIP2018模拟A组9.25】到不了——动态LCA裸题
题目描述 Description wy 和 wjk 是好朋友. 今天他们在一起聊天,突然聊到了以前一起唱过的<到不了>. "说到到不了,我给你讲一个故事吧." &quo ...
- NOIp2018模拟赛三十六
好久没打模拟赛了...今天一样是两道国集,一道bzoj题 成绩:13+0+95=108 A题开始看错题了...导致样例都没看懂,结果xfz提醒我后我理解了一个我自认为正确的题意(事实证明我和xfz都错 ...
- EZ 2018 03 09 NOIP2018 模拟赛(三)
最近挺久没写比赛类的blog了 链接:http://211.140.156.254:2333/contest/59 这次的题目主要考验的是爆搜+打表的能力 其实如果你上来就把所有题目都看过一次就可以知 ...
- NOIp2018模拟赛三十八
爆〇啦~ A题C题不会写,B题头铁写正解: 随手过拍很自信,出分一看挂成零. 若要问我为什么?gtmdsubtask! 神tm就一个subtask要么0分要么100,结果我预处理少了一点当场去世 难受 ...
- NOIp2018模拟赛三十七
奇怪的一场... 前两题都是全场题,C题明显不可做,我题目都没看懂...(STO lhx OTZ) 成绩:100+100+8=208 貌似十几个208的...A题暴力$O(nmc)$能过...暴力容斥 ...
- NOIp2018模拟赛三十五
两道大数据结构把我砸懵 成绩:未提交 Orz xfz两道正解 A:[BZOJ4049][CREC2014B]mountainous landscape B:CJB的大作(CF改编题)
- NOIp2018模拟赛三十三
神奇的一场... 成绩:100+0+14=114 A题是个体面很恐怖的题...然而看懂题意之后转化一下就变成了一道暴力傻逼题...但是不知道为什么dalao们都没写,讲题的时候挺尴尬的...yrx“瞄 ...
- NOIp2018模拟赛三十二
继续挂成傻逼 成绩:100+0+10(90)=110 A全场一眼题,C没取模挂八十分,然后没特判特殊情况又挂十分 A:[agc009b]tournament(太简单,咕了) B:[ATC2142]Bu ...
随机推荐
- LA 3635 Pie
题意:给出n个圆,分给n+1个人,求每个人最多能够得到多大面积的圆 二分每个人得到的圆的面积 #include<iostream> #include<cstdio> #incl ...
- github踩坑之git命令收集与整理(windows)
最近开始又捡起git,第一家公司用的就是git,一直掌握的也不深刻,就知道常用的几个命令,虽然现在用svn,但是觉得git还是不能丢,遂又捡起来了.先总结一部分目前练习用到的,慢慢填补吧~ githu ...
- Codeforces Round #499 (Div. 2) D. Rocket_交互题_二分
第一次作交互题,有点不习惯. 由于序列是循环的,我们可以将一半的机会用于判断当前是否是在说谎,另一半的机会用于二分的判断. 对于判断是否实在说谎,用1判断即可.因为不可能有比1还小的数. 本题虽然非常 ...
- 利用请求的JSON数据创建图形图层
先看效果图: 包含三个部分:信息窗口(标题是要素的某个属性信息,其余是感兴趣的属性信息).图上图形按照某一属性大小不一显示,图例 1.创建底图用于存放以上三部分: "esri/Map&quo ...
- u-boot启动代码start.S详解360
(1)定义入口.由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本 ...
- vue文件目录结构
使用node和npm环境,很容易搭建起一个vue环境.搭建完成以后,项目基本结构,如下图所示: 1.build: bulid文件夹保存的是一些webpack的初始化配置 2.config: confi ...
- jQuery 事件流的概念
jQuery 事件流的概念 什么是事件流 DOM事件流 1. 事件捕获阶段; 2.处于目标阶段; 3.事件冒泡阶段; <!DOCTYPE html> <html lang=&quo ...
- 小学生都能学会的python(<lamda匿名函数,sorted(),filter(),map(),递归函数>)
小学生都能学会的python(<<lamda匿名函数,sorted(),filter(),map(),递归函数,二分法>> 1. lambda 匿名函数 lambda 参数: ...
- zoj 3471 Most Powerful(状压dp+Tsp问题+连续性问题)
上来直接一波敲键盘,直接套Tsp问题的代码 然后WA 发现貌似这道题没有连续性. Tsp问题是一条路径,一个点到另一个点,多了一个限制,所以就需要加多一维 而这道题没有限制,也就是说那一维不需要加,我 ...
- SQL SERVER-identity | @@identity | scope_identity
主键自增 IDENTITY(1,1),MS SQL Server 使用 IDENTITY 关键字来执行 auto-increment 任务. 在上面的实例中,IDENTITY 的开始值是 1,每条新记 ...