[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 ...
随机推荐
- Struts2连接Mysql的Crud使用
今天分享的是struts2框架中增删改查的用法: 一:利用Struts2框架 1.1在pom.xml中导入相关依赖 <project xmlns="http://maven.apach ...
- k8s系列0--Kubernetes基础知识
Kubernetes介绍 参考:Kubernetes核心组件解析 Pod是k8s的最小调度单元 每个pod有独立的IP,但是pod的IP是不可靠的,重新调度pod就会改变IP,service概念就是为 ...
- hdu 5212 反向容斥或者莫比
http://acm.hdu.edu.cn/showproblem.php?pid=5212 题意:忽略.. 题解:把题目转化为求每个gcd的贡献.(http://www.cnblogs.com/z1 ...
- CAS 5.x搭建常见问题系列(3).Failure to find org.apereo.cas:cas-server-support-pm-jdbc:jar:5.1.9
错误内容 cas overlay的pom.xml增加了cas-server-support-pm-jdbc.jary依赖后, 打包(mvn package)出现如下的报错 D:\casoverlay\ ...
- 一篇文章彻底搞懂异步,同步,setTimeout,Promise,async
之前翻看别的大佬的博客看到了关于setTimeout,promise还有async执行顺序的文章.观看了几篇之后还是没有怎么看懂,于是自己开始分析代码,并整理了此文章,我相信通过此文章朋友们能对异步同 ...
- 【原创】大叔经验分享(84)spark sql中设置hive.exec.max.dynamic.partitions无效
spark 2.4 spark sql中执行 set hive.exec.max.dynamic.partitions=10000; 后再执行sql依然会报错: org.apache.hadoop.h ...
- luogu题解P1967货车运输--树链剖分
题目链接 https://www.luogu.org/problemnew/show/P1967 分析 NOIp的一道裸题,直接在最大生成树上剖分取最小值一下就完事了,非常好写,常数也比较小,然而题解 ...
- Java数据结构总述
array list map set 链表..array 和list类似,增删慢,读取快,list长度可变,array长度固定, 链表增删快的list set 是一个没有重复数据的集合 map 是一个 ...
- UIApplicationDelegate里面最常用的几个函数执行顺序小结
(1)点击桌面图标正常启动App或者杀死进程后点击推送消息启动App 1.application:willFinishLaunchingWithOptions 2.application:applic ...
- 【appium】appium中的元素定位和基本操作
# coding=utf-8 from appium import webdriver import time from selenium.webdriver.support.ui import We ...