[BZOJ3626] [LNOI2014] LCA 离线 树链剖分
考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\)。
显然这些LCA一定在\(z\)到根的路径上。下面的问题就是怎么统计。
考虑不是那么暴力的暴力。
我们似乎可以把\(1..r\)的所有点先瞎搞一下,求出一个点内部有几个\(1..r\)以内的点,记作\(w[i]\)。另假设\(fson[x]\)表示\(x\)的孩子中\(z\)这个点所在孩子
那么答案就是
\]
发现\(x\)有多少祖先,\(dep[x]\)就是几。所以可以把\(w[x]-w[son[x]]\)放到其所有祖先上各统计一次。
这样就发现,被减掉的\(w[fson[x]]\)又会被后面的继续加回来。
所以最终答案就是
\]
那么,如果维护这个\(w[x]\)呢?
从小到大循环\(1..n\),(也就是循环的是询问的差分后的那个\(r\)指针)然后只需要把\(i\)的祖先都更新一个\(1\)就可以了,然后枚举挂在\(i\)上的询问,统计从\(z\)到根的路径和。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define REP(i,a,n) for(register int i(a);i<=(n);++i)
#define FEC(i,x,y) for(register int i=head[x],y=g[i].to;i;i=g[i].ne,y=g[i].to)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
#define lc o<<1
#define rc o<<1|1
const int SZ=(1<<21)+1;char ibuf[SZ],*iS,*iT,obuf[SZ],*oS=obuf,*oT=obuf+SZ-1;
#ifdef ONLINE_JUDGE
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SZ,stdin),(iS==iT?EOF:*iS++)):*iS++)
#else
#define gc() getchar()
#endif
template<typename I>inline void read(I&x){char c=gc();int f=0;for(;c<'0'||c>'9';c=gc())c=='-'?f=1:0;for(x=0;c>='0'&&c<='9';c=gc())x=(x<<1)+(x<<3)+(c&15);f?x=-x:0;}
inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
#define printf(...) (iS>iT&&(flush(),1),oS+=sprintf(oS,__VA_ARGS__))
template<typename A,typename B>inline char SMAX(A&a,const B&b){return a<b?a=b,1:0;}
template<typename A,typename B>inline char SMIN(A&a,const B&b){return a>b?a=b,1:0;}
typedef long long ll;
const int N=50000+7,P=201314;
int n,m,x,y,z,ans[N];
int dep[N],f[N],num[N],son[N],top[N],dfn[N],pre[N],dfc;
struct Edge{int to,ne;}g[N];int head[N],tot;
inline void Addedge(int x,int y){g[++tot].to=y;g[tot].ne=head[x];head[x]=tot;}
struct Questions{int opt,r,z,*ans;inline char operator<(const Questions&a)const{return r<a.r;}}q[N<<1];
inline int SMOD(int x){return x>=P?x-P:x;}
inline void SADD(int&x,const int&y){x+=y;x>=P?x-=P:0;}
inline void SDEL(int&x,const int&y){x-=y;x<0?x+=P:0;}
inline void DFS1(int x,int fa=0){
dep[x]=dep[fa]+1;f[x]=fa;num[x]=1;
FEC(i,x,y)if(y!=fa){DFS1(y,x);num[x]+=num[y];if(num[y]>num[son[x]])son[x]=y;}
}
inline void DFS2(int x,int pa){
top[x]=pa;dfn[x]=++dfc;pre[dfc]=x;
if(!son[x])return;DFS2(son[x],pa);
FEC(i,x,y)if(y!=f[x]&&y!=son[x])DFS2(y,y);
}
struct Node{int sum,add;}t[N<<2];
inline void Add(int o,int L,int R,int l,int r){
if(l<=L&&R<=r)return SADD(t[o].add,1),SADD(t[o].sum,R-L+1);
int M=(L+R)>>1;if(l<=M)Add(lc,L,M,l,r);if(r>M)Add(rc,M+1,R,l,r);
t[o].sum=SMOD(t[lc].sum+t[rc].sum);SADD(t[o].sum,t[o].add*(R-L+1)%P);//错误笔记:Pushup的时候要记得更新标记
}inline void Add(int l,int r){Add(1,1,n,l,r);}
inline int Sum(int o,int L,int R,int l,int r,int k=0){
if(l<=L&&R<=r)return SMOD(t[o].sum+(ll)(R-L+1)*k%P);
int M=(L+R)>>1;if(r<=M)return Sum(lc,L,M,l,r,SMOD(k+t[o].add));else if(l>M)return Sum(rc,M+1,R,l,r,SMOD(t[o].add+k));
else return SMOD(Sum(lc,L,M,l,r,SMOD(k+t[o].add))+Sum(rc,M+1,R,l,r,SMOD(t[o].add+k)));
}inline int Sum(int l,int r){return Sum(1,1,n,l,r);}
inline void Modify(int x){
while(top[x]!=1){Add(dfn[top[x]],dfn[x]);x=f[top[x]];}
Add(dfn[1],dfn[x]);
}
inline int Query(int x){
int ans=0;while(top[x]!=1){SADD(ans,Sum(dfn[top[x]],dfn[x]));x=f[top[x]];}
return SMOD(ans+Sum(dfn[1],dfn[x]));
}
int main(){
read(n),read(m);
REP(i,2,n)read(x),Addedge(x+1,i);
REP(i,1,m)read(x),read(y),read(z),++x,++y,++z,q[(i<<1)-1]=Questions{1,y,z,ans+i},q[i<<1]=Questions{-1,x-1,z,ans+i};
std::sort(q+1,q+(m<<1)+1);DFS1(1);DFS2(1,1);int p=1;
while(p<=(m<<1)&&!q[p].r)++p;//错误笔记: 要跳过之前以0开头没有用的空询问
REP(i,1,n){
Modify(i);
while(p<=(m<<1)&&q[p].r==i)~q[p].opt?SADD(*q[p].ans,Query(q[p].z)):SDEL(*q[p].ans,Query(q[p].z)),++p;
}
REP(i,1,m)printf("%d\n",ans[i]);
return flush(),0;
}
[BZOJ3626] [LNOI2014] LCA 离线 树链剖分的更多相关文章
- 2018.09.16 bzoj3626: [LNOI2014]LCA(树链剖分)
传送门 树链剖分好题. 对于每个点维护一个值vi" role="presentation" style="position: relative;"&g ...
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
[BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
- BZOJ3626: [LNOI2014]LCA(树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- bzoj3626: [LNOI2014]LCA (树链剖分)
很神奇的方法 感觉是有生之年都想不到正解的这种 考虑对i 到根的节点权值 + 1,则从根到z的路径和就是lca(i,z)的深度 所以依次把0 ~ n - 1的点权值 + 1 对于询问[l, r] 这个 ...
- 【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
[BZOJ3626]LCA(树链剖分,Link-Cut Tree) 题面 Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. ...
- BZOJ 3626 LCA(离线+树链剖分)
首先注意到这样一个事实. 树上两个点(u,v)的LCA的深度,可以转化为先将u到根路径点权都加1,然后求v到根路径上的总点权值. 并且该题支持离线.那么我们可以把一个区间询问拆成两个前缀和形式的询问. ...
- [BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】
题目链接: BZOJ - 3626 题目分析 考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就 ...
- 【洛谷 P4211】[LNOI2014]LCA(树链剖分,差分)
题目链接 看到题目肯定首先想到要求LCA(其实是我菜),可乍一看,n与q的规模为5W, 求LCA的复杂度为\(O(logN)\),那么总时间复杂度为\(O(nq\ log\ n)\). 怎么搞呢? 会 ...
随机推荐
- BUUCTF | [CISCN2019 华北赛区 Day1 Web2]ikun
步骤: 找到lv6的购买出,修改折扣买lv6 :然后找到admin的登陆界面,JWT破解,登陆admin :点击一键成为大会员,利用python反序列化漏洞读取flag 解析: 这题师傅们的WP已经很 ...
- git commit --amend用法(摘抄)
适用场景: 比方说,你的代码已经提交到git库,leader审核的时候发现有个Java文件代码有点问题,于是让你修改,通常有2种方法: 方法1:leader 将你提交的所有代码 abandon掉,然后 ...
- 洛谷P1288 取数游戏II(博弈)
洛谷P1288 取数游戏II 先手必胜的条件需要满足如下中至少 \(1\) 条: 从初始位置向左走到第一个 \(0\) 的位置,经过边的数目为偶数(包含 \(0\) 这条边). 从初始位置向右走到第一 ...
- selenuim&PhantomJS&Beautifulsoup练习经典实例
# coding = utf-8__autor__ = 'litao' from selenium import webdriverfrom selenium.webdriver.common.by ...
- Linux学习篇(一)-初识Linux
开源许可协议 简单了解开源许可协议,一张图读懂. linux 系统特点 linux 特点安全性高.高可用.高性能 稳定且有效率 免费或少许免费 漏洞少且快速修补 多任务多用户 更加安全的用户及文件权限 ...
- C#-概念-类库:类库
ylbtech-C#-概念-类库:类库 1.返回顶部 1. 类库(Class Library)是一个综合性的面向对象的可重用类型集合,这些类型包括:接口.抽象类和具体类.类库可以解决一系列常见编程任务 ...
- Hadoop HDFS本地存储目录结构解析
转自:https://blog.csdn.net/superman_xxx/article/details/51689398 HDFS metadata以树状结构存储整个HDFS上的文件和目录,以及相 ...
- ubuntu搭建jdk+jenkins
第一步,安装jdk(如果已安装,直接进行第二步) 1.下载 jdk-8u172-linux-x64.tar.gz 点此下载 2.解压 tar -zxvf jdk-8u172-linux ...
- Git - 暂存区及撤销修改
1. 暂存区 每个 Git 仓库中,都有一个隐藏目录 .git 用于存放 Git 仓库的相关信息,包括暂存区(称为 stage).自动创建的 master 分支以及指向 master 分支的 HEAD ...
- mysql内存数据淘汰机制和大查询会不会把内存打爆?
首先我们说一下大查询会不会把内存打爆? 比如说主机内存有5g,但是我们一个大查询的数据有10g,这样会不会把内存打爆呢? 答案:不会 为什么? 因为mysql读取数据是采取边读边发的策略 select ...