BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626
直接引用清华爷gconeice的题解吧
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 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<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=;
const long long modn=;
const long long minf=<<;
int n,m;
struct nod{
int y,next;
}e[maxn];int head[maxn]={},tot=;
int fa[maxn]={},top[maxn]={},pos[maxn]={},kid[maxn]={},dep[maxn]={};
void init(int x,int y){
e[++tot].y=y;e[tot].next=head[x];head[x]=tot;
}
int dfs1(int x){
int y,hug=,siz,tsn=;dep[x]=dep[fa[x]]+;
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
if(y==fa[x])continue;
siz=dfs1(y);
if(siz>hug)hug=siz,kid[x]=y;
tsn+=siz;
}return tsn;
}
void dfs2(int x,int pa){
int y;top[x]=pa;pos[x]=++tot;
if(kid[x])dfs2(kid[x],pa);
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
if(y==kid[x]||y==fa[x])continue;
dfs2(y,y);
}
}
struct seg{
long long sum,w,l,r;
seg(){sum=l=r=;}
}t[maxn*];
void build(int x,int l,int r){
t[x].l=l;t[x].r=r;
if(l==r)return;
int mid=(l+r)/;
build(x*,l,mid);
build(x*+,mid+,r);
}
void pushup(int x){
if(t[x].r>t[x].l)t[x].sum=t[x*].sum+t[x*+].sum;
t[x].sum+=(t[x].r-t[x].l+)*t[x].w;
}
void add(int x,int l,int r){
if(l<=t[x].l&&t[x].r<=r){
if(t[x].l==t[x].r)t[x].sum+=;
else {t[x].w+=;pushup(x);}
return;
}
int mid=(t[x].l+t[x].r)/,ls=x*,rs=x*+;
if(r>mid) add(rs,l,r);
if(l<=mid) add(ls,l,r);
pushup(x);
}
long long sum(int x,int l,int r,int w){
if(l<=t[x].l&&t[x].r<=r)return t[x].sum+w*(t[x].r-t[x].l+);
int mid=(t[x].l+t[x].r)/,ls=x*,rs=x*+;long long tsn=;
if(l<=mid) tsn+=sum(ls,l,r,w+t[x].w);
if(r>mid) tsn+=sum(rs,l,r,w+t[x].w);
return tsn;
}
long long doit(int x){
int a=top[x];long long tsn=;
for(;a!=;){
tsn+=sum(,pos[a],pos[x],);
x=fa[a];a=top[x];
}
tsn+=sum(,pos[a],pos[x],);
return tsn;
}
void datup(int x){
int a=top[x];
for(;a!=;){
add(,pos[a],pos[x]);
x=fa[a];a=top[x];
}
add(,pos[a],pos[x]);
}
struct lcc{
int num;
int z;int id;
long long ans;
}q[maxn*];
bool cmp1(lcc aa,lcc bb){return aa.num<bb.num;}
bool cmp2(lcc aa,lcc bb){return aa.id<bb.id;}
int main(){
scanf("%d%d",&n,&m);
int x,y,z;
for(int i=;i<n;i++){
scanf("%d",&y);
init(y+,i+);
fa[i+]=y+;
}tot=;dfs1();dfs2(,);build(,,n);tot=;
for(int j=;j<=m;j++){
scanf("%d%d%d",&x,&y,&z);
x++;y++;z++;
if(y<x)swap(x,y);
q[++tot].num=x-;q[tot].z=z;q[tot].id=tot;
q[++tot].num=y;q[tot].z=z;q[tot].id=tot;
}sort(q+,q++tot,cmp1);
int now=;
for(int i=;i<=tot;i++){
while(now<q[i].num){
now++;datup(now);
}
q[i].ans=doit(q[i].z);
}
sort(q+,q++tot,cmp2);
for(int i=;i<=m;i++){
long long z=(q[i*].ans-q[i*-].ans)%;
printf("%lld\n",z);
}
return ;
}
BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线的更多相关文章
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
随机推荐
- 设计模式之Composite
设计模式总共有23种模式这仅仅是为了一个目的:解耦+解耦+解耦...(高内聚低耦合满足开闭原则) Composite定义? 将对象以树形结构组织起来,以达成“部分-整体” 的层次结构. 想到Compo ...
- 远程工具(SSH Secure)连接Centos出现中文乱码问题的解决办法
问题原因 使用远程工具进行连接时,如果linux有中文文件或目录,显示时会出现乱码,原因是linux编码是UTF-8,而远程工具默认是当前系统本地编码即GBK.所以解决方案是统一两者编码就OK了,但是 ...
- 145.Binary Tree Postorder Traversal---二叉树后序非递归遍历
题目链接 题目大意:后序遍历二叉树. 法一:普通递归,只是这里需要传入一个list来存储遍历结果.代码如下(耗时1ms): public List<Integer> postorderTr ...
- ifconfig与内核通信 ifreq 结构体分析和使用
结构原型: /* * Interface request structure used for socket * ioctl's. All interface ioctl's must have p ...
- 运行级别(run level)
inittab是很多linux版本的启动脚本.Linux在完成核内引导以后,就开始运行init程序,它的进程号是1,是所有其他进程的起点.init需要读取/etc/inittab,该文件告诉init在 ...
- HDU 2894 DeBruijin (数位欧拉)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2894 题目大意:旋转鼓的表面分成m块扇形,如图所示(m=8).图中阴影区表示用导电材料制成,空白区用绝 ...
- 20165301实验二java面向对象程序设计
20165301实验二java面向对象程序设计 实验目的与要求(提交点一): 参考http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTEST完成单 ...
- poj 1077(BFS预处理+康托展开)
Eight Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 29935 Accepted: 13029 Special ...
- java中Property类的基本用法
1 配置.properties文件 2 获取输入流的方法 1)FileInputStream fi = new FileInputStream(properties文件路径); 2)InputStre ...
- Hadoop案例(三)找博客共同好友
找博客共同好友案例 1)数据准备 以下是博客的好友列表数据,冒号前是一个用户,冒号后是该用户的所有好友(数据中的好友关系是单向的) A:B,C,D,F,E,O B:A,C,E,K C:F,A,D,I ...