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

5 2
0
0
1
1
1 4 3
1 4 2

Sample Output

8
5

HINT

共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。

Source

数据已加强 by saffah

Solution

先是两篇高端的题解:HZW学长  TimeMachine学长

什么LCA,都是骗人的

直接暴力去做,很显然不可以,那么这必然会有一些性质或者转化使之简便

那么考虑一种其他的做法

离线处理,把每个询问拆成两个部分,分别是【1~l-1】和【1~r】那么前缀和?

那么维护一下信息,即z点到根的路径

然后加每个点的时候是把从这个点到根的路径的点权全部+1,然后查询就是查询某个点到根的路径的点权和

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 树链剖分的更多相关文章

  1. BZOJ 3626 离线+树链剖分+线段树

    思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...

  2. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  3. Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)

    Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)↗[GO!] 题意 是说有棵树,每个节点上 ...

  4. [BZOJ3626] [LNOI2014]LCA(树链剖分)

    [BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...

  5. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  6. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  7. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...

  8. BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

    http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...

  9. BZOJ 3626 [LNOI2014]LCA ——树链剖分

    思路转化很巧妙. 首先把询问做差分. 然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和. 这样和原问题是等价的,然后树链剖分+线段树就可以做了. #include <map ...

  10. BZOJ 3083 遥远的国度(树链剖分+LCA)

    Description 描述zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度.当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要z ...

随机推荐

  1. zookeeper多节点配置

    单机多节点模式 zookeeper解压, 放到 /opt/zookeeper/ 下, 同目录再放一个 server1目录, 下面建data和log两个目录用于存放数据和日志 zoo.cfg [milt ...

  2. 01Spring_基本jia包的导入andSpring的整体架构and怎么加入日志功能

    1.什么是Spring : v\:* {behavior:url(#default#VML);} o\:* {behavior:url(#default#VML);} w\:* {behavior:u ...

  3. swift 定时器的使用

    在swift中,要使用定时器就需要用到对象NSTimer.通过NSTimer的实例化后,就可以调用fire方法来启用了. NSTimer有2个构造函数 init(timeInterval ti: NS ...

  4. Castle.ActiveRecord 多对多关系 引发的错误处理

    在Castle.ActiveRecord 实体类中,如果两个对象有 “多对多” 关系,一般的做法是将其分解为 两个“一对多”关系,但有时引发了 “您要删除 或 引用 的对象#2在数据库中不存在”的异常 ...

  5. mvc route的注册,激活,调用流程

    mvc route的注册,激活,调用流程(三) net core mvc route的注册,激活,调用流程 mvc的入口是route,当前请求的url匹配到合适的route之后,mvc根据route所 ...

  6. 路由系统的核心对象——Router

    路由系统的核心对象--Router ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路 ...

  7. QT 数据库编程一

    QT如果要进行网络编程首先需要在.pro中添加如下代码:QT += network //logindlg.h #ifndef LOGINDLG_H #define LOGINDLG_H #includ ...

  8. 自己的兼容IE系列的console.log

    console.log.apply 在某些浏览器下无法通过if进行验证,只能通过try catch进行验证: window.zlogs = function(){ try{ window.consol ...

  9. VS编译器优化诱发一个的Bug

    VS编译器优化诱发一个的Bug Bug的背景 我正在把某个C++下的驱动程序移植到C下,前几天发生了一个比较诡异的问题. 驱动程序有一个bug,但是这个bug只能 Win32 Release 版本下的 ...

  10. 用linqPad帮助你快速学习LINQ

    在这里我向大家推荐的一个具是LinqPad有了这个工具并熟练使用就可以很快学习并掌握linq linqPad下载地址:http://www.linqpad.net/ 它也自带了很多例子方便大家查询,l ...