[LNOI2014] LCA
题目描述:
网址:http://www.lydsy.com/JudgeOnline/problem.php?id=3626
大意:
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。
一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求\(∑dep[LCA(i,z)],{l<=i<=r}\)。
---(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
题目解法:
考虑求\(LCA(i,z)\),z是不变的。
那么如果把 \(i到root的路径\) 权值加1,最后答案就为 \(z到root路径\) 上的权值和。
这是一个常见的套路啦。
因为这个我们可以对每一次的询问进行差分。
查询答案变为\(Ans = Query(R) - Query(L-1);\)
这样就可以离线做:
我们从左往右依次增加 1~N到root的路径权值 ,然后 查询对应相关询问中 z到root路径 的权值和即可。
所有东西都直接用LCT维护即可。
实现代码
#include<bits/stdc++.h>
#define ll long long
#define RG register
#define IL inline
#define maxn 60000
#define mod 201314
using namespace std;
IL ll gi(){
RG ll date = 0, m = 1; RG char ch = 0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch = getchar();
if(ch == '-'){m = -1; ch = getchar();}
while(ch>='0' && ch<='9')
{date=date*10+ch-'0'; ch = getchar();}
return date*m;
}
ll N,Q,root; struct Question {ll L,R,Z;}qs[maxn];
ll ch[maxn][2],fa[maxn],rev[maxn],sum[maxn],sz[maxn],laz[maxn],val[maxn];
vector<ll>gpL[maxn],gpR[maxn]; ll stk[maxn];
IL bool Son(RG ll x){return ch[fa[x]][1] == x;}
IL bool Isroot(RG ll x){return (ch[fa[x]][1] != x && ch[fa[x]][0] != x);}
IL bool Reverse(RG ll x){swap(ch[x][0],ch[x][1]); rev[x]^=1;}
IL void PushUp(RG ll x){
sum[x] = ( val[x] + sum[ch[x][0]] + sum[ch[x][1]] )%mod;
sz[x] = 1 + sz[ch[x][0]] + sz[ch[x][1]];
}
IL void PushDown(RG ll x){
RG ll ls = ch[x][0],rs = ch[x][1];
if(laz[x]){
sum[ls] = (sum[ls] + 1ll*laz[x]*sz[ls])%mod;
sum[rs] = (sum[rs] + 1ll*laz[x]*sz[rs])%mod;
val[ls] = (val[ls] + laz[x])%mod;
val[rs] = (val[rs] + laz[x])%mod;
laz[ls] = (laz[x] + laz[ls])%mod;
laz[rs] = (laz[x] + laz[rs])%mod;
laz[x] = 0;
}
if(rev[x]){ Reverse(ls); Reverse(rs);rev[x] ^= 1; }
}
IL void Rot(RG ll x){
RG ll y = fa[x],z = fa[y],c = Son(x);
if(!Isroot(y))ch[z][Son(y)] = x; fa[x] = z;
ch[y][c] = ch[x][!c]; fa[ch[y][c]] = y;
ch[x][!c] = y; fa[y] = x; PushUp(y);
}
IL void Splay(RG ll x){
stk[++stk[0]] = x;
for(RG ll y = x; !Isroot(y); y = fa[y])stk[++stk[0]] = fa[y];
while(stk[0])PushDown(stk[stk[0]--]);
for(RG ll y = fa[x]; !Isroot(x); Rot(x),y = fa[x])
if(!Isroot(y))Son(x) ^ Son(y) ? Rot(x) : Rot(y);
PushUp(x);
}
IL void Access(RG ll x){ for(RG ll y = 0; x; y = x,x = fa[x])Splay(x),ch[x][1] = y,PushUp(x); }
IL void Makeroot(RG ll x){ Access(x); Splay(x); Reverse(x); }
IL void Split(RG ll x,RG ll y){ Makeroot(x); Access(y); Splay(y); }
IL void Link(RG ll x,RG ll y){ Makeroot(x); fa[x] = y; }
//已经把所有点的标号都加了1。
int main(){
N = gi(); Q = gi();
for(RG ll i = 1; i <= N; i ++)sz[i] = 1;
for(RG ll i = 2; i <= N ; i ++)Link(gi()+1,i);
for(RG ll i = 1; i <= Q ; i ++){
qs[i].L = (gi()-1)+1; qs[i].R = gi()+1; qs[i].Z = gi()+1;
gpL[qs[i].L].push_back(i);
gpR[qs[i].R].push_back(i);
}
root = 1;
for(RG ll i = 1; i <= N; i ++){
Split(root,i);
val[i]++; laz[i]++;
sum[i] = sum[i] + sz[i];
for(RG ll j = 0,c; j < gpL[i].size(); j ++)
c = gpL[i][j] ,Split(root,qs[c].Z) , qs[c].L = sum[qs[c].Z];
for(RG ll j = 0,c; j < gpR[i].size(); j ++)
c = gpR[i][j] ,Split(root,qs[c].Z) , qs[c].R = sum[qs[c].Z];
}
for(RG ll i = 1; i <= Q; i ++)
printf("%lld\n",(qs[i].R - qs[i].L + mod)%mod);
return 0;
}
[LNOI2014] LCA的更多相关文章
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...
- 洛谷 P4211 [LNOI2014]LCA 解题报告
[LNOI2014]LCA 题意 给一个\(n(\le 50000)\)节点的有根树,询问\(l,r,z\),求\(\sum_{l\le i\le r}dep[lca(i,z)]\) 一直想启发式合并 ...
- P4211 [LNOI2014]LCA
P4211 [LNOI2014]LCA 链接 分析: 首先一种比较有趣的转化是,将所有点到1的路径上都+1,然后z到1的路径上的和,就是所有答案的deep的和. 对于多次询问,要么考虑有把询问离线,省 ...
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
[BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...
- P4211 [LNOI2014]LCA LCT
P4211 [LNOI2014]LCA 链接 loj luogu 思路 多次询问\(\sum\limits_{l \leq i \leq r}dep[LCA(i,z)]\) 可以转化成l到r上的点到根 ...
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- [bzoj3626][LNOI2014]LCA
Description 给出一个$n$个节点的有根树(编号为$0$到$n-1$,根节点为$0$). 一个点的深度定义为这个节点到根的距离$+1$. 设$dep[i]$表示点$i$的深度,$lca(i, ...
随机推荐
- [Python Study Notes] 编程仪式感的Hello World!
学习还是要有一点仪式感的,学单片机第一步,点个灯:学编程第一步,hello world! C:\Users\Liu>python Python 3.6.4 (v3.6.4:d48eceb, De ...
- 关于Git的版本问题
问题的起源 我在IDEA上不小心修改了文件(加了一行空行)并且被保存了,在GitHub Desktop桌面工具上可以看到changes中有修改记录,并且使用命令行git status也可以看到文件的修 ...
- map,vector 等容器内容的循环删除问题(C++)
map,vector 等容器内容的循环删除问题(C++) map,vector等容器的循环删除不能用普通的方法删除: for(auto p=list.begin();p!=list.end();p++ ...
- 洛谷P2286 [HNOI2004]宠物收养场【Treap】题解+AC代码
题目传送门啦~啦~啦~ 题目描述 凡凡开了一间宠物收养场.收养场提供两种服务:收养被主人遗弃的宠物和让新的主人领养这些宠物. 每个领养者都希望领养到自己满意的宠物,凡凡根据领养者的要求通过他自己发明的 ...
- Head First C 笔记
嗨翻c语言 1. 入门 为什么字符从零开始编号? 字符的索引数值表示的是一个偏移量,它表示的是当前所引用的字符与第一个字符之间差多少个字符. 单双引号的区别? 单引号 一个字符,双- 字符串 字符串字 ...
- js获取某个日期所在周周一的日期
第一次写,做个小笔记. 第一步:获取该日期的星期数: 第二步:在该日期上减去他的星期数再减1,(注:星期日获取到的星期数是0): 下面是具体代码: function GetMonday(dd) { v ...
- Egret学习笔记 (Egret打飞机-2.开始游戏)
打开 Egret Wing,新建一个Egret游戏项目,然后删掉默认生成的createGameScene方法里面的东西 然后新建一个BeginScene.ts的文件,作为我们的游戏的第一个场景 cla ...
- 关于C/S框架网单表绑定,查询
这种绑定暂时支持单表,并且不支持主键自增长!保存,删除,查看,修改用框架现成的. 1.先生成tb.bll.dal三个类.框架有生成工具,在debug文件里面有个叫CSFramework.Tools.C ...
- 实战小项目BUG纪录
果然,作为程序员最可爱的女朋友就是各种BUG,解决了你的开发能力和开发效率就会上升到一个新的层次.反之,在你面对BUG的时候,如果轻易的就放弃了,你也就失去了一次自我成长的机会.学习就是这样的,我们有 ...
- Docker系统六:Docker网络管理
Docker网络 I. Docer的通信方式 默认情况下,Docker使用网桥(brige)+ NAT的通信模型. Docker启动时会自动创建网桥Docker0,并配置ip 172.17.0.1/1 ...