这题好神啊

能够\(1A\)真是不可思议

首先看到要求的这个柿子\(\sum_{i=l}^{r}deep[LCA(i,z)]\),而且\(l\)和\(r\)并不是来自与一棵子树或者一条链,而是编号连续的一段

所以肯定没有什么办法可以一下子求出来这么多的\(LCA\)的

得想个好的办法转化一下

于是就想往主席树上想

首先\(z\)的\(lca\)肯定是在\(z\)到根的路径上的,于是我们可以定住\(lca\),来求这个\(lca\)对答案的贡献

于是我们有一个主席树的暴力

我们就枚举\(z\)到根的路径上的点,对于这些每一个点,我们求出在其子树内部有多少个大于\(l\)小于\(r\)的点,乘上深度,这就是这个\(lca\)的贡献

吗?

显然不是,我们得减去那些在下面的那些子树里就已经算过了的数

所以我们会暴力啦,真开心

那我们想一下如何优化暴力

先来看看答案长什么样子

好吧,我画的还是很难看,这可是魏佬钦定

我们设\(sum_i\)表示在\(i\)的子树内部有多少个符合条件的点

于是我们的答案可以写成

\[4*sum_4+3*(sum_3-sum_4)+2*(sum_2-sum_3)+1*(sum_1-sum_2)
\]

之后就会惊奇的发现答案竟然就是\(sum_4+sum_3+sum_2+sum_1\)

那我们怎么维护啊,难道要硬上主席树?

显然不用啊

既然没有强制在线,我们就离线+树剖呗

一个点显然只会对他本身到根上这条路径的点产生贡献,于是就是一个树剖板子了

同时查询也是一个简单的根路径查询

至于如何统计答案,我们将询问排序,之后可以将插入顺序想象成时间轴,于是就可以差分求解了

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define re register
#define maxn 50005
const int mod=201314;
struct E
{
int v,nxt;
}e[maxn<<1];
struct Ask
{
int x,y,z,rk;
}a[maxn];
int n,m,num,Q,cnt;
int top[maxn],deep[maxn],fa[maxn],to[maxn],sum[maxn],son[maxn],head[maxn];
int l[maxn<<2],r[maxn<<2],tag[maxn<<2],d[maxn<<2];
int Lans[maxn],Rans[maxn];
inline void add_edge(int x,int y)
{
e[++num].v=y;
e[num].nxt=head[x];
head[x]=num;
}
inline int read()
{
char c=getchar();
int x=0;
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-48,c=getchar();
return x;
}
void build(int x,int y,int i)
{
l[i]=x,r[i]=y,d[i]=0,tag[i]=0;
if(x==y) return;
int mid=x+y>>1;
build(x,mid,i<<1),build(mid+1,y,i<<1|1);
}
inline void pushdown(int i)
{
if(!tag[i]) return;
tag[i<<1]+=tag[i];
if(tag[i<<1]>mod) tag[i<<1]%=mod;
tag[i<<1|1]+=tag[i];
if(tag[i<<1|1]>mod) tag[i<<1|1]%=mod;
d[i<<1]+=(r[i<<1]-l[i<<1]+1)*tag[i];
d[i<<1]%=mod;
d[i<<1|1]+=(r[i<<1|1]-l[i<<1|1]+1)*tag[i];
d[i<<1|1]%=mod;
tag[i]=0;
}
void change(int x,int y,int i)
{
if(x<=l[i]&&y>=r[i])
{
tag[i]++;
d[i]+=r[i]-l[i]+1;
if(d[i]>mod) d[i]%=mod;
return;
}
pushdown(i);
int mid=l[i]+r[i]>>1;
if(y<=mid) change(x,y,i<<1);
else if(x>mid) change(x,y,i<<1|1);
else change(x,y,i<<1),change(x,y,i<<1|1);
d[i]=(d[i<<1]+d[i<<1|1])%mod;
}
int query(int x,int y,int i)
{
if(x<=l[i]&&y>=r[i]) return d[i];
pushdown(i);
int mid=l[i]+r[i]>>1;
if(y<=mid) return query(x,y,i<<1);
if(x>mid) return query(x,y,i<<1|1);
return (query(x,y,i<<1)+query(x,y,i<<1|1))%mod;
}
void dfs1(int x)
{
sum[x]=1;
int maxx=-1;
for(re int i=head[x];i;i=e[i].nxt)
if(!deep[e[i].v])
{
deep[e[i].v]=deep[x]+1;
fa[e[i].v]=x;
dfs1(e[i].v);
sum[x]+=sum[e[i].v];
if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
}
}
void dfs2(int x,int topf)
{
top[x]=topf;
to[x]=++cnt;
if(!son[x]) return;
dfs2(son[x],topf);
for(re int i=head[x];i;i=e[i].nxt)
if(deep[e[i].v]>deep[x]&&son[x]!=e[i].v) dfs2(e[i].v,e[i].v);
}
inline void tree_change(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
change(to[top[x]],to[x],1);
x=fa[top[x]];
}
if(deep[x]>deep[y]) std::swap(x,y);
change(to[x],to[y],1);
}
inline int tree_query(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
ans+=query(to[top[x]],to[x],1);
if(ans>mod) ans%=mod;
x=fa[top[x]];
}
if(deep[x]>deep[y]) std::swap(x,y);
ans+=query(to[x],to[y],1);
return ans%mod;
}
inline int cmp(Ask K,Ask M)
{
return K.x<M.x;
}
inline int cop(Ask K,Ask M)
{
return K.y<M.y;
}
int main()
{
n=read(),Q=read();
int Fa;
for(re int i=1;i<n;i++)
Fa=read(),add_edge(Fa,i);
deep[0]=1;
dfs1(0);
dfs2(0,0);
build(1,n,1);
for(re int i=1;i<=Q;i++)
a[i].x=read(),a[i].y=read(),a[i].z=read(),a[i].rk=i;
std::sort(a+1,a+Q+1,cmp);
int tot=1;
for(re int i=-1;i<n;i++)
{
if(i>=0) tree_change(i,0);
while(a[tot].x-1==i)
{
Lans[a[tot].rk]=tree_query(a[tot].z,0);
tot++;
}
}
build(1,n,1);
std::sort(a+1,a+Q+1,cop);
tot=1;
for(re int i=0;i<n;i++)
{
tree_change(i,0);
while(a[tot].y==i)
{
Rans[a[tot].rk]=tree_query(a[tot].z,0);
tot++;
}
}
for(re int i=1;i<=Q;i++)
printf("%d\n",(Rans[i]-Lans[i]+mod)%mod);
return 0;
}

【[LNOI2014]LCA】的更多相关文章

  1. [SPOJ913]QTREE2 - Query on a tree II【倍增LCA】

    题目描述 [传送门] 题目大意 给一棵树,有两种操作: 求(u,v)路径的距离. 求以u为起点,v为终点的第k的节点. 分析 比较简单的倍增LCA模板题. 首先对于第一问,我们只需要预处理出根节点到各 ...

  2. 【Tarjan,LCA】【3-21个人赛】【problemD】

    Problem D Time Limit : 6000/3000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other) Total Sub ...

  3. POJ3694 Network【连通分量+LCA】

    题意: 一个无向图可以有重边,下面q个操作,每次在两个点间连接一条有向边,每次连接后整个无向图还剩下多少桥(注意是要考虑之前连了的边,每次回答是在上一次的基础之上). 思路: 首先运行一次Tarjan ...

  4. 【最小生成树+LCA】Imperial roads

    http://codeforces.com/gym/101889 I 先跑一遍最小生成树,把经过的边和答案记录下来 对于每个询问的边,显然如果处于MST中,答案不变 如果不在MST中,假设这条边连上了 ...

  5. 【Targan+LCA】HDU 3686 Traffic Real Time Query

    题目内容 洛谷链接 给出一个\(n\)个节点,\(m\)条边的无向图和两个节点\(s\)和\(t\),问这两个节点的路径中有几个点必须经过. 输入格式 第一行是\(n\)和\(m\). 接下来\(m\ ...

  6. 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树

    [BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...

  7. bzoj3626【LNOI2014】LCA

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1266  Solved: 448 [Submit][Stat ...

  8. 【POJ 3694】 Network(割边&lt;桥&gt;+LCA)

    [POJ 3694] Network(割边+LCA) Network Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7971 ...

  9. 【LCA】BZOJ1776-[Usaco2010 Hol]cowpol 奶牛政坛

    [题目大意] 一棵n个点的树,树上每个点属于一个党派,要求每个党派的最远距离点.两点间距离为两点间边的个数. [思路] yy一下可知,最远距离点中必有一个是该党派深度最深的一个,那么我们就记下最深的点 ...

随机推荐

  1. Knockout.js Text绑定

    <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...

  2. C# DateTime类型和sqlserver DateTime精度不同

    在最近的项目中, 有个关于时间的功能.一个请假的时间.前端选择的时候只有日期.所以比如请一天假就是选2017-8-15和2017-8-15,这样算请这一天的假.但是后台存入数据库时我不能就存2017- ...

  3. 【原】Spring和Dubbo基于XML配置整合过程

    背景 随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进. 单一应用架构 当网站流量很小时,只需一个 ...

  4. linux ubuntu 学习总结(day01)基本命令学习

    个人总结,请尊重版权,转载请在显眼地方注明出处:https://www.cnblogs.com/sunshine5683/p/9948259.html day(01)基本命令学习 今天开始自学linu ...

  5. POJ 1006 Biorhythms --中国剩余定理(互质的)

    Biorhythms Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 103539   Accepted: 32012 Des ...

  6. python学习之老男孩python全栈第九期_day020知识点总结——序列化模块、模块的导入和使用

    一. 序列化模块 # 序列化 --> 将原本的字典.列表等内容转换成一个字符串的过程就叫做序列化# 反序列化 --> 从字符串转换成数据类型的过程叫做反序列化# 序列 -- 字符串 # 什 ...

  7. Jquery中动态生成的元素没有点击事件或者只有一次点击事件

    今天用jq做动态生成的元素的click事件时,click只执行了一次,当然有些朋友可能根本没执行, 执行了一次的原因是因为可能有函数加载了一遍,一次都没执行的可能是没绑定对象或者jq版本问题, 动态生 ...

  8. HDU P2222 Keywords Search

    In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.Wiskey als ...

  9. ASP.NET MVC学习笔记 第三天

    布局: 如果不使用布局页,需要将Layout属性设置为null. @{     Layout = null; } 使用默认布局页: 使用Add View对话框,选择使用布局页(是布局页的名称文本框为空 ...

  10. Python with VS Code

    1. 基本的代码结构为: 2.