[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 ...
随机推荐
- spring cloud微服务实践七
在spring cloud 2.x以后,由于zuul一直停滞在1.x版本,所以spring官方就自己开发了一个项目 Spring Cloud Gateway.作为spring cloud微服务的网关组 ...
- SAS学习笔记11 SAS宏
宏是一个被储存的文本,用一个名字识别它.最简单的宏就像一个宏变量一样工作,但复杂的宏可以完成许多宏变量不能做的事. 定义宏的语句格式为: %macro 宏名称: 宏文本 %mend <宏名称&g ...
- CentOS7离线安装Mysql(详细安装过程)
Mysql安装 下载mysql离线安装包 https://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.27-1.el7.x86_64.rpm-bundle ...
- Comet OJ - Contest #5 迫真图论 (图分块)
大意: 给定无向图, 点$i$点权$b_i$, 边$(x,y,z)$对序列贡献是把$A[b_x \oplus b_y]$加上$z$. 多组询问, 一共三种操作: 1. 修改点权. 2.修改边权. 3. ...
- (五)CXF之添加拦截器
一.需求分析 webService中的拦截器类似于servlet的Filter过滤器.一般用于调用服务前后先调用拦截器的方法. 二.案例 本章案例是基于上一章节的基础上添加拦截器的 2.1 服务端添加 ...
- 调用顺丰API实现电商专递下单和获取面单功能
参考文章:https://www.cnblogs.com/zhangxiaoyong/p/8317229.html 顺丰需求文档: 链接:https://pan.baidu.com/s/16EEaph ...
- Vibe
在读研和工作之间徘徊了半年,看着一个个好友工作.保研,生活安排得井井有条,我也是时候收拾心情,整装前进了.既然选择了图像,就一定要好好做下去. 今天开始第一个算法,Vibe. ViBe是一种像素级视频 ...
- C#使用Selenium网页自动化
工作中很多时候经常需要网抓数据或者把数据填写到网站上,使用Selenium将其自动化是一种不错的选择.Selenium其实是一个用于Web应用程序测试的工具,测试你的应用程序看是否能够很好地工作在不同 ...
- MySQL操作规范总结
来源:静以致远√团团 用户权限管理创建用户命令:CREATE USER 'username'@'host' IDENTIFIED BY 'password';说明:Username所创建的用户名hos ...
- django中解决跨域问题
-跨域问题 -浏览器的:同源策略,浏览器拒绝不是当前域域返回的数据 -ip地址和端口号都相同才是同一个域 -如何解决: -CORS:跨域资源共享 -简单请求:发一次请求 -非简单请求:非简单请求是发送 ...