【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 ...
随机推荐
- Javascript中document.execCommand()的用法
document.execCommand()方法处理Html数据时常用语法格式如下:document.execCommand(sCommand[,交互方式, 动态参数]) 其中:sCommand为指令 ...
- AlwaysOn Group Listener
1.Listener是什么 Listener实际上是一个 VirtualNetworkName,客户端通过这个VNN来连接的具体的sqlserver实例 .Listener包含了DNS名称,port和 ...
- [转]解决GET请求时中文乱码的问题
原文地址:http://www.cnblogs.com/liukemng/p/4178882.html 之前项目中的web.xml中的编码设置: <filter> <filter-n ...
- Java7并发编程实战(一) 守护线程的创建和运行
Java里有一种特殊的线程叫做守护(Daemon)线程,这种线程的优先级很低,通常来说,当一个应用程序里面没有其他线程运行的时候,守护线程才运行,当线程是程序中唯一运行的线程时,守护线程执行结束后,J ...
- python2.1-原理之琐碎技巧
本系列依据<python学习手册第四版>而写,也算是个学习笔记吧,选择本书的原因在于它不同于第三版,它强调介绍python3.0 ,而会在不同的地方给出2.6版本的区别,:本书侧重介绍原理 ...
- canvas中的碰撞检测笔记
用 canvas 做小游戏或者特效,碰撞检测是少不了的.本文将会涉及普通的碰撞检测,以及像素级的碰撞检测.(本文的碰撞检测均以矩形为例) 普通碰撞检测 普通的矩形碰撞检测比较简单.即已知两个矩形的各顶 ...
- .NET C#微信公众号开发远程断点调试(本地远程调试生产环境代码)
最近在做微信公众号开发,由于之前没有接触过,突然发现调试不方便,不方便进行断点跟踪调试.因为微信那边绑定的服务器地址必须是公网地址,但是还是想进行断点调试(毕竟这样太方便了,程序有Bug,一步步断点跟 ...
- 为什么带网格(mesh)的模型添加了刚体Rigidbody和MeshCollider,还是会从地板穿过去?
两个Gameobject 放置在空中, 一个是Cube,一个是茄子模型 Cube的Collider 是Box Collider , 茄汁的Collider 是mesh collider, 他们都添加了 ...
- C#操作Excel时的格式设定(转)
Excel报表打印的格式设定 1. 表头的设置 Excel._Worksheet myWorksheet; myWorksheet.PageSetup.Orientation = Excel. ...
- [转]搞ACM的你伤不起(转自Roba大神)
劳资六年前开始搞ACM啊!!!!!!!!!! 从此踏上了尼玛不归路啊!!!!!!!!!!!! 谁特么跟劳资讲算法是程序设计的核心啊!!!!!! 尼玛除了面试题就没见过用算法的地方啊!!!!!! 谁再跟 ...