[Luogu] LCA
https://www.luogu.org/problemnew/show/P4211
baoli
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring> using namespace std;
const int N = 5e4 + ;
const int Mod = ; #define gc getchar() #define RR freopen("gg.in", "r", stdin) int fa[N] = {-}, deep[N], cnt[N], head[N];
struct Node {int u, v, nxt;} G[N];
int n, Ty, now = ; inline int read() {
int x = ; char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' && c <= '') x = x * + c - '', c = gc;
return x;
} inline void Add(int u, int v) {
G[now].u = u; G[now].v = v; G[now].nxt = head[u]; head[u] = now ++;
} void Dfs(int u, int dep) {
deep[u] = dep;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u]) Dfs(v, dep + );
}
} void Dfs_2(int u) {
if(head[u] == -) return ;
for(int i = head[u]; ~ i; i = G[i].nxt) {
int v = G[i].v;
if(v != fa[u]) {
Dfs_2(v);
cnt[u] += cnt[v];
}
}
} int main() {
n = read();
Ty = read();
for(int i = ; i < n; i ++) head[i] = -;
for(int i = ; i < n; i ++) {
int u = read(); fa[i] = u;
Add(u, i); Add(i, u);
}
Dfs(, );
while(Ty --) {
int l = read(); int r = read(); int z = read();
for(int i = l; i <= r; i ++) cnt[i] ++;
Dfs_2();
int imp = z;
int Answer = ;
while(fa[imp] != -) {
Answer += cnt[imp];
Answer %= Mod;
imp = fa[imp];
} Answer += cnt[imp];
Answer %= Mod;
cout << Answer << endl;
memset(cnt, , sizeof cnt);
}
return ;
}
考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就是从 y 到 Root 的路径上的点权和。
这个方法是可以叠加的,这是非常有用的一点。如果我们把 [l, r] 的每个点到 Root 的路径上所有点的权值 +1,再求出从 c 到 Root 的路径点权和,即为 [l, r] 中所有点与 c 的 LCA 的 Depth 和。
不仅满足可加性,还满足可减性,这就更好了!
那么我们就可以对每个询问 [l, r] 做一个差分,用 Query(r) - Query(l - 1) 作为答案。这样就有一种离线算法:将 n 个点依次操作,将其到 Root 的路径上的点权值 +1 ,然后如果这个点是某个询问的 l - 1 或 r ,就用那个询问的 c 求一下到 Root 的路径和,算入答案中。
#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 50005
#define M 201314
#define K 150005
using namespace std;
struct graph {
int nxt,to;
} e[N];
struct quest {
int x,z,n,ans;
} l[N],r[N];
struct linetree {
int l,r,s,len,lzy;
} lt[K];
int g[N],n,q,t1,t2,cnt;
int f[N],p[N],dep[N],top[N],siz[N],son[N];
inline int read() {
int ret=;
char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c)) {
ret=(ret<<)+(ret<<)+c-'';
c=getchar();
}
return ret;
}
inline void addedge(int x,int y) {
e[++cnt].nxt=g[x];
g[x]=cnt;
e[cnt].to=y;
}
inline void dfs1(int u) {
int m=;
siz[u]=;
for(int i=g[u]; i; i=e[i].nxt) {
f[e[i].to]=u;
dep[e[i].to]=dep[u]+;
dfs1(e[i].to);
siz[u]+=siz[e[i].to];
if(siz[e[i].to]>m) {
son[u]=e[i].to;
m=siz[e[i].to];
}
}
}
inline void dfs2(int u,int tp) {
top[u]=tp;
p[u]=++cnt;
if(son[u]) dfs2(son[u],tp);
for(int i=g[u]; i; i=e[i].nxt)
if(e[i].to!=son[u])
dfs2(e[i].to,e[i].to);
}
inline void build(int u,int l,int r) {
lt[u].l=l;
lt[u].r=r;
lt[u].len=lt[u].r-lt[u].l+;
if(lt[u].l<lt[u].r) {
int lef=u<<,rig=u<<|;
int mid=lt[u].l+lt[u].r>>;
build(lef,l,mid);
build(rig,mid+,r);
}
}
inline int cover(int u,int l,int r) {
if(lt[u].l>=l&<[u].r<=r) {
++lt[u].lzy;
lt[u].s=(lt[u].s+lt[u].len)%M;
} else if(lt[u].l<lt[u].r) {
int lef=u<<,rig=u<<|;
int mid=lt[u].l+lt[u].r>>;
if(lt[u].lzy) {
lt[lef].lzy+=lt[u].lzy;
lt[rig].lzy+=lt[u].lzy;
lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M;
lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M;
lt[u].lzy=;
}
if(l<=mid) cover(lef,l,r);
if(r>mid) cover(rig,l,r);
lt[u].s=(lt[lef].s+lt[rig].s)%M;
}
}
inline int ask(int u,int l,int r) {
if(lt[u].l>=l&<[u].r<=r)
return lt[u].s;
if(lt[u].l<lt[u].r) {
int lef=u<<,rig=u<<|,ret=;
int mid=lt[u].l+lt[u].r>>;
if(lt[u].lzy) {
lt[lef].lzy+=lt[u].lzy;
lt[rig].lzy+=lt[u].lzy;
lt[lef].s=(lt[lef].s+lt[lef].len*lt[u].lzy)%M;
lt[rig].s=(lt[rig].s+lt[rig].len*lt[u].lzy)%M;
lt[u].lzy=;
}
if(l<=mid) ret=(ret+ask(lef,l,r))%M;
if(r>mid) ret=(ret+ask(rig,l,r))%M;
return ret;
}
}
inline void add(int x,int y) {
int t;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) {
t=x;
x=y;
y=t;
}
cover(,p[top[x]],p[x]);
x=f[top[x]];
}
if(p[x]>p[y]) {
t=x;
x=y;
y=t;
}
cover(,p[x],p[y]);
}
inline int que(int x,int y) {
int ret=,t;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) {
t=x;
x=y;
y=t;
}
ret=(ret+ask(,p[top[x]],p[x]))%M;
x=f[top[x]];
}
if(p[x]>p[y]) {
t=x;
x=y;
y=t;
}
ret=(ret+ask(,p[x],p[y]))%M;
return ret;
}
inline bool cmp1(quest x,quest y) {
return x.x<y.x;
} inline bool cmp2(quest x,quest y) {
return x.n<y.n;
}
inline void Aireen() {
n=read();
q=read();
for(int i=,j; i<=n; ++i) {
j=read()+;
addedge(j,i);
}
for(int i=; i<=q; ++i) {
l[i].n=r[i].n=i;
l[i].x=read();
r[i].x=read()+;
l[i].z=r[i].z=read()+;
}
sort(l+,l++q,cmp1);
sort(r+,r++q,cmp1);
while(t1<=q&&!l[t1].x) ++t1;
while(t2<=q&&!r[t2].x) ++t2;
dep[]=;
dfs1();
cnt=;
dfs2(,);
build(,,n);
for(int i=; i<=n; ++i) {
add(,i);
while(t1<=q&&l[t1].x==i) {
l[t1].ans=que(,l[t1].z);
++t1;
}
while(t2<=q&&r[t2].x==i) {
r[t2].ans=que(,r[t2].z);
++t2;
}
}
sort(l+,l++q,cmp2);
sort(r+,r++q,cmp2);
for(int i=; i<=q; ++i)
printf("%d\n",(r[i].ans-l[i].ans+M)%M);
}
int main() {
Aireen();
fclose(stdin);
fclose(stdout);
return ;
}
[Luogu] LCA的更多相关文章
- 【OI】倍增求LCA
╭(′▽`)╯ 总之,我们都知道lca是啥,不需要任何基础也能想出来怎么用最暴力的方法求LCA,也就是深度深的点先跳到深度浅的点的同一深度,然后一起向上一步步跳.这样显然太慢了! 所以我们要用倍增,倍 ...
- Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集)
Luogu 2245 星际导航(最小生成树,最近公共祖先LCA,并查集) Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为 ...
- Luogu P4211 [LNOI2014]LCA
我去这道题的Luogu评级是假的吧,这都算黑题. 我们首先考虑把操作离线不强制在线的题目离线一下一般都要方便些 考虑差分,我们用\(f(x)\)表示\([1,x]\)之间的点与\(z\)的答案,那么显 ...
- Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分)
Luogu 2680 NOIP 2015 运输计划(树链剖分,LCA,树状数组,树的重心,二分,差分) Description L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之 ...
- Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)
Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...
- 【Luogu P3379】LCA问题的倍增解法
Luogu P3379 题意:对于两个节点,寻找他们的最近公共祖先. 一个显而易见的解法是对于每一个节点我们都往上遍历一遍,记录下它每一个祖先,然后再从另一个节点出发,一步一步往上走,找到以前记录过第 ...
- [luogu]P1600 天天爱跑步[LCA]
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
- 货车运输 noip2013 luogu P1967 (最大生成树+倍增LCA)
luogu题目传送门! 首先,题目让我们求每个货车的最大运输量,翻译一下就是求路径上边权最小的边. 利用一下贪心思想可知,所有货车肯定都会尽量往大的边走. 进一步翻译,即为有一些小边货车根本不会走,或 ...
- [NOIP 2016D2T2/Luogu P1600] 天天爱跑步 (LCA+差分)
待填坑 Code //Luogu P1600 天天爱跑步 //Apr,4th,2018 //树上差分+LCA #include<iostream> #include<cstdio&g ...
随机推荐
- (1+x)^n
#include<stdio.h> int main() { int n,i; while(scanf("%d %d",&n,&i)!=EOF) { i ...
- MySQL中的索引详讲(转)
https://www.cnblogs.com/whgk/p/6179612.html
- Golang语言编程规范
Golang语言编程规范 一.说明 编程规范好,可避免语言陷阱,可有利团队协作,有利项目维护. 正常的Go编程规范有两种:编译器强制的(必须的),gofmt格式化非强制的(非必须). Go宣告支持驼峰 ...
- Django rest-framework框架-组件之渲染器
渲染器: from rest_framework.renderers import BrowsableAPIRenderer,AdminRenderer,HTMLFormRenderer,JSONRe ...
- 二、eureka服务端注册服务
所有文章 https://www.cnblogs.com/lay2017/p/11908715.html 正文 入口 上文我们说到,eureka是使用jersey来对外提供restful风格的rpc调 ...
- iOS热更新实现方式
heart.jpg 苹果静止热更新,可惜我的是企业app,没有这些约束了,随便用.(当然有些热更新已经可以通过苹果审核了,比如JSPatch)官网说的: JSPatch 平台 SDK 1.7.2 以上 ...
- sql复杂的子查询,横向合并结果集
第一个查询的结果集 select * from( select c.msName,a.msId,c.msPrice, c.msPrice*COUNT(a.msId) as totalMoney,sum ...
- 阿里P7分享如何面对枯燥的源码
一个软件开发人员,工作到了一定的年限(一般是3.4年左右),如果他还没学会阅读源码,那么他就会遇到瓶颈.因为到了这个时候的开发,他应该不仅仅只会做那些 CURD 的业务逻辑,而应该会根据公司的实际情况 ...
- rabbit MQ 的环境及命令使用(一)
RabbitMQ依赖erlang,所以先安装erlang,然后再安装RabbitMQ; 先安装erlang,双击erlang的安装文件即可,然后配置环境变量: ERLANG_HOME=D:\Progr ...
- C#的预处理指令