[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 ...
随机推荐
- Redis键的基本操作
1.Redis键的键名查询 ·命令名称:KEYS ·语法:KEYS pattern ·Pattern的用法: ? 任意一个字符 * 任意个任意字符 [ae] a或者e [^ae] 除了a和e [a-c ...
- javascript 正则表达式的简单操作
前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! RegExp 正则表达式是描述字符模式的对象. 正则表达式用于对字符串模式匹配及检索替换,是对字符串执行模 ...
- Unity性能优化-DrawCall
1. DrawCall是啥?其实就是对底层图形程序(比如:OpenGL ES)接口的调用,以在屏幕上画出东西.所以,是谁去调用这些接口呢?CPU.比如有上千个物体,每一个的渲染都需要去调用一次底层接口 ...
- (八)mybatis之多对多
一.需求分析 需求:查询所有用户的信息以及每个用户所属的组的信息 分析:一个用户可以有多个组,一个组也可以由多个用户. 多对多,可以设置一张中间表,该表存放的是用户表和组表的对应关系. 二.创建数据库 ...
- 数据结构-平衡二叉树Java实现
1,Node.java package com.cnblogs.mufasa.BalanceBinaryTree; public class Node { Node parent; Node left ...
- QTabWidget标签实现双击关闭(转)
重载了QTabWidget(由于tabBar()是protected),这样就可以获取到标签了. 1 class Tab : public QTabWidget 2 { 3 Q_OBJECT 4 pu ...
- 根据导入xlxs的文件,来写入数据库
今天讲解一下上传文件.前台必须保持传参类型"multipart/form-data" 后台可以设定 public static final String MULTIPART_FOR ...
- 五、HashMap的使用 及其源码解析
HashMap的底层实现原理?领接表(数组+链表)hash表数组+链表+红黑树 链表:查找慢 插入 删除快红黑树:查找快 插入 删除慢 HashMap是线程安全的吗?不是线程安全的 在什么情况下 ,是 ...
- Go 字符串使用
Go语言中的字符串 Go 中的字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码,这样每一个Unicode字符根据代码点的大小使用1.2.3或4个字节表示代码点.Go 语言中的字符串 ...
- leetcode-3 最长无重复字串
3. Longest Substring Without Repeating Characters 题面 Given a string, find the length of the longest ...