【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 ...
随机推荐
- ES6 WeakSet数据结构 与Set十分相似
它与Set十分相似,对象的值也不能是重复的,与Set不同点: .WeakSet成员只能够是对象. .作为WeakSet成员的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说, ...
- 浅析jQuery删除节点的三个方法
jQuery提供了三种删除节点的方法,即remove(),detach()和empty().测试所用HTML代码:[html] view plaincopy<p title="选择你最 ...
- usb驱动开发17之设备生命线
拜会完了山头的几位大哥,还记得我们从哪里来要到哪里去吗?时刻不能忘记自身的使命啊.我们是从usb_submit_urb()最后的那个遗留问题usb_hcd_submit_urb()函数一路走来,现在就 ...
- jquery选择器空格与大于号、加号与波浪号的区别
空格:$('parent childchild')表示获取parent下的所有的childchild节点,所有的子孙. 大于号:$('parent > child')表示获取parent下的所有 ...
- jboss eap 6.3 集群(cluster)配置
接上一篇继续,Domain模式解决了统一管理多台jboss的问题,今天我们来学习如何利用mod_cluster来实现负载均衡.容错. mod_cluster是jboss的一个开源集群模块(基于apac ...
- 完美演绎DevExpress XtraPrinting Library 的打印功能
完美演绎DevExpress XtraPrinting Library 的打印功能 2010-05-14 17:40:49| 分类: 默认分类|字号 订阅 设计报告不仅费时间,而且还乏味!但 ...
- 利用PowerShell+Jenkins,实现项目的自动化部署
当项目越来越庞大,部署环境越来越多以后,就会越来越依赖于自动化.比如本人公司的项目,目前有6个web和4个windows service,同时本地有两套环境:开发自测试环境和QA测试环境.每次版本发布 ...
- centos7 安装nginx和php5.6.25遇到 无法访问php页面 报错file not found 问题解决
php-fpm安装完成,nginx安装完成 netstap -ntl| 发下端口正常开启 iptables -L 返现9000端口已经开放 ps -aux|grep nginx 发下nginx进程正常 ...
- Windows 10 后台音频
UWP版本的网易云音乐已经上架,虽然还不支持Windows Phone但是整体而言功能已经比较齐全了! 那么如何在Windows 10 UWP实现后台播放呢? 我之前是一直在做Windows Phon ...
- 转一篇Unity的相机动画控制
最近真是忙,连研究细看的时间都没有了,原帖地址:https://alastaira.wordpress.com/2013/11/08/smooth-unity-camera-transitions-w ...