【BZOJ-3626】LCA 树链剖分
3626: [LNOI2014]LCA
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1428 Solved: 526
[Submit][Status][Discuss]
Description
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
0
0
1
1
1 4 3
1 4 2
Sample Output
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
Source
Solution
先是两篇高端的题解:HZW学长 TimeMachine学长
什么LCA,都是骗人的
直接暴力去做,很显然不可以,那么这必然会有一些性质或者转化使之简便
那么考虑一种其他的做法
离线处理,把每个询问拆成两个部分,分别是【1~l-1】和【1~r】那么前缀和?
那么维护一下信息,即z点到根的路径
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define mod 201314
#define maxn 100100
#define maxq 100100
struct Edgenode{int to,next;}edge[maxn];
int head[maxn],cnt;int n,q,zz;
void add(int u,int v)
{cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
//
int size[maxn],pre[maxn],deep[maxn],son[maxn],fa[maxn],pl[maxn],sz,pr[maxn],top[maxn];
void dfs_1(int x)
{
size[x]=;
for(int i=head[x];i;i=edge[i].next)
if (edge[i].to!=fa[x])
{
deep[edge[i].to]=deep[x]+;
fa[edge[i].to]=x;
dfs_1(edge[i].to);
size[x]+=size[edge[i].to];
}
}
void dfs_2(int x,int chain)
{
top[x]=chain; pl[x]=++sz;
int k=n;
for(int i=head[x];i;i=edge[i].next)
if(edge[i].to!=fa[x]&&size[edge[i].to]>size[k])
k=edge[i].to;
if(k!=n) dfs_2(k,chain);
for(int i=head[x];i;i=edge[i].next)
if(edge[i].to!=fa[x]&&edge[i].to!=k)
dfs_2(edge[i].to,edge[i].to);
}
//
struct Treenode{int l,r,tag,da;}tree[maxn<<];
inline void update(int now)
{tree[now].da=tree[now<<].da+tree[now<<|].da;}
inline void pushdown(int now)
{
int l=tree[now].l,r=tree[now].r,tag=tree[now].tag;
int mid=(l+r)>>,ln=mid-l+,rn=r-mid;
if (tag)
{
tree[now].tag=;
tree[now<<].tag+=tag; tree[now<<|].tag+=tag;
tree[now<<].da+=ln*tag; tree[now<<|].da+=rn*tag;
}
}
void build(int now,int l,int r)
{
tree[now].tag=tree[now].da=;
tree[now].l=l;tree[now].r=r;
if (l==r) return;
int mid=(l+r)>>;
build(now<<,l,mid); build(now<<|,mid+,r);
}
void segment_change(int now,int L,int R)
{
pushdown(now);
if (L<=tree[now].l && R>=tree[now].r)
{tree[now].da+=(tree[now].r-tree[now].l+);tree[now].tag++;return;}
int mid=(tree[now].l+tree[now].r)>>;
if (L<=mid) segment_change(now<<,L,R);
if (R>mid) segment_change(now<<|,L,R);
update(now);
}
int segment_ask(int now,int L,int R)
{
pushdown(now);
if (L<=tree[now].l && R>=tree[now].r) return tree[now].da;
int mid=(tree[now].l+tree[now].r)>>; int ans=;
if (L<=mid) ans+=segment_ask(now<<,L,R);
if (R>mid) ans+=segment_ask(now<<|,L,R);
return ans;
} //
void change(int x,int y)
{
while (top[x]!=top[y])
{
segment_change(,pl[top[x]],pl[x]);
x=fa[top[x]];
}
segment_change(,pl[y],pl[x]);
}
int query(int x,int y)
{
int ans=;
while (top[x]!=top[y])
{
ans=(ans+segment_ask(,pl[top[x]],pl[x]))%mod;
x=fa[top[x]];
}
ans=(ans+segment_ask(,pl[y],pl[x]))%mod;
return ans;
}
//
struct Asknode{int z,ans1,ans2;}ask[maxq];
struct Reqnode
{
int p,id;bool f;
bool operator < (const Reqnode & A) const
{return p<A.p;}
}req[maxq<<];
int main()
{
// freopen("3626.in","r",stdin);
// freopen("3626.out","w",stdout);
n=read(),q=read();
for (int x,i=; i<=n-; i++)
x=read(),add(x,i);
for (int a,b,c,i=; i<=q; i++)
{
a=read(),b=read(),c=read();
ask[i].z=c;
zz++;req[zz].p=a-;req[zz].id=i;req[zz].f=;
zz++;req[zz].p=b;req[zz].id=i;req[zz].f=;
}
sort(req+,req+zz+);
// for (int i=1; i<=zz; i++)
// printf("%d %d %d\n",req[i].p,req[i].id,req[i].f);
build(,,n); dfs_1(); dfs_2(,);
// for (int i=0; i<=n; i++)
// printf("%d %d %d %d %d %d\n",i,fa[i],deep[i],pl[i],size[i],top[i]);
int now=-;
for (int i=; i<=zz; i++)
{
while (now<req[i].p)
now++,change(now,);
// printf("%d\n",query(ask[req[i].id].z,0));
if (!req[i].f) ask[req[i].id].ans1=query(ask[req[i].id].z,);
else ask[req[i].id].ans2=query(ask[req[i].id].z,);
}
for (int i=; i<=q; i++)
printf("%d\n",(ask[i].ans2-ask[i].ans1+mod)%mod);
return ;
}
sb错误毁一生!!!!
数据生成器:
#include<cstdio>
#include<ctime>
#include<cstdlib>
using namespace std;
int main()
{
freopen("3626.in","w",stdout);
int n;
srand(time());
// scanf("%d",&n);
n=;
printf("%d %d\n",n,n);
for (int i=;i<=n-;i++)
printf("%d\n",rand()%(i+));
for (int i=;i<=n;i++)
printf("%d %d %d\n",rand()%n,rand()%n,rand()%n);
return ;
}
【BZOJ-3626】LCA 树链剖分的更多相关文章
- BZOJ 3626 离线+树链剖分+线段树
思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
- Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)
Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)↗[GO!] 题意 是说有棵树,每个节点上 ...
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
- BZOJ 3626 [LNOI2014]LCA ——树链剖分
思路转化很巧妙. 首先把询问做差分. 然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和. 这样和原问题是等价的,然后树链剖分+线段树就可以做了. #include <map ...
- BZOJ 3083 遥远的国度(树链剖分+LCA)
Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...
随机推荐
- dotnetGen 系列终于开源了
https://github.com/2881099/dotnetGen .Net 3.0 + SqlServer 生成器 https://github.com/2881099/dotnetGen_s ...
- Web服务器父与子 Apache和Tomcat区别
http://developer.51cto.com/art/201007/210894.htm 熟悉三国的朋友都知道曹操,曹操有二十五个儿子,其中最得曹操宠爱的是曹丕.曹植.曹彰三个,曹丕性格阴冷, ...
- Tree Traversals
Tree Traversals 原题链接 常见的二叉树遍历的题目,根据后序遍历和中序遍历求层次遍历. 通过后序遍历和中序遍历建立起一棵二叉树,然后层序遍历一下,主要难点在于树的建立,通过中序遍历和后序 ...
- android中常用的读取文件的用法如下
1. 从resource的raw中读取文件数据: String res = ""; try{ //得到资源中的Raw数据流 InputStream in = getResource ...
- JavaScript中的类型转换(二)
说明: 本篇主要讨论JavaScript中各运算符对运算数进行的类型转换的影响,本文中所提到的对象类型仅指JavaScript预定义的类型和程序员自己实现的对象,不包括宿主环境定义的特殊对象(比如浏览 ...
- 最佳实践 —— 详细谈谈如何减小APK体积
转载请注明出处: http://www.cnblogs.com/soaringEveryday/p/5254520.html 随着Android移动开发的需求越来越复杂,我们不可避免的遇到发布出去的a ...
- .net异步编程
现在电脑大部分都是多核心,在处理多线程方便有很大优势,异步调用方法的时候可以立即返回执行其他程序,进行异步编程会让程序运行效率更高. 我也是刚刚关注异步编程方面知识,也有很多不是很理解,所以想向大神请 ...
- Debian8修改启动默认运行级别
Two things you need to know: 1) Systemd boots towards the target given by "default.target" ...
- C#版的MapReduce
如果不知道MapReduce是怎么工作的,请看这里,如果不知道MapReduce是什么,请google之! 今天“闲”来无事,忽想起C#里没有MapReduce的方法,构思之,coding之: #re ...
- OpenStack 简介
OpenStack是IaaS(基础设施即服务)组件,让任何人都可以自行建立和提供云端运算服务. 此外,OpenStack也用作建立防火墙内的"私有云"(Private Cloud) ...