[hdu5266]区间LCA
题意:给一棵树,求节点L,L+1,...R的最近公共祖先
思路:先对树dfs一下,从根1出发,经过每条边时记录一下终点和到达这个点的时间截,令r[u]表示到达u这个节点的最早时间截,t[x]表示在时间截x时到达的节点编号,假设对于两个节点u,v,设r[u]<r[v],则在t[r[u]], t[r[u]+1], ..., t[r[v]]这个序列里面一定包含了u和v的LCA。要找出这个LCA也不难,由于这个序列里面的所有节点只有u和v的LCA这个节点的r值最小,于是可以用RMQ求出这个最小r值,然后再利用t数组就得到了LCA的节点编号。对于多个节点的LCA处理方法类似,只需找到多个节点中的r值的最小和最大值,相当于找到了r[u]和r[v],剩下的就与两个点的LCA一样了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
#pragma comment(linker, "/STACK:10240000,10240000") #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <algorithm> #include <queue> using namespace std; const int maxn = 3e5 + 7; struct Graph { vector<vector< int > > G; void clear() { G.clear(); } void resize( int n) { G.resize(n + 2); } vector< int > & operator [] ( int x) { return G[x]; } int size() { return G.size(); } void add( int u, int v) { G[u].push_back(v); } }; Graph G; struct ST { struct FI { int a[21]; int & operator [] ( int x) { return a[x]; } }; vector<FI> dp; vector< int > T; void init( int a[], int n, int (*F)( int , int )) { dp.clear(); dp.resize(n); for ( int i = 0; i < n; i ++) dp[i][0] = a[i]; for ( int j = 1; (1 << j) <= n; j ++) { for ( int i = 0; i + (1 << j) - 1 < n; i ++) { dp[i][j] = F(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } T.clear(); T.resize(n); T[1] = 0; for ( int i = 2; i <= n; i ++) { T[i] = T[i - 1]; if ((i & (i - 1)) == 0) T[i] ++; } } int query( int L, int R, int (*F)( int , int )) { int t = T[R - L + 1]; return F(dp[L][t], dp[R - (1 << t) + 1][t]); } }; int fmin( int a, int b) { return a < b? a : b; } int fmax( int a, int b) { return a > b? a : b; } struct LCA { int clock , r[maxn], t[2 * maxn], b[2 * maxn]; bool vis[maxn]; ST st0, st1, st2; void dfs( int rt) { r[rt] = clock ; t[ clock ++] = rt; vis[rt] = true ; int sz = G[rt].size(); for ( int i = 0; i < sz; i ++) { int u = G[rt][i]; if (!vis[u]) { dfs(u); t[ clock ++] = rt; } } } void work() { clock = 0; memset (vis, 0, sizeof (vis)); dfs(1); for ( int i = 0; i < clock ; i ++) b[i] = r[t[i]]; st0.init(b, clock , fmin); st1.init(r + 1, ( clock + 1) >> 1, fmax); st2.init(r + 1, ( clock + 1) >> 1, fmin); } int lca_all( int L, int R) { L --; R --; int lp = st2.query(L, R, fmin), rp = st1.query(L, R, fmax); return t[st0.query(lp, rp, fmin)]; } }; LCA lca; int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); #endif // ONLINE_JUDGE int n, m; while (cin >> n) { G.clear(); G.resize(n); for ( int i = 0; i < n - 1; i ++) { int u, v; scanf ( "%d%d" , &u, &v); G.add(u, v); G.add(v, u); } lca.work(); cin >> m; for ( int i = 0; i < m; i ++) { int L, R; scanf ( "%d%d" , &L, &R); printf ( "%d\n" , lca.lca_all(L, R)); } } return 0; } |
[hdu5266]区间LCA的更多相关文章
- HDU 5266 pog loves szh III(区间LCA)
题目链接 pog loves szh III 题意就是 求一个区间所有点的$LCA$. 我们把$1$到$n$的$DFS$序全部求出来……然后设$i$的$DFS$序为$c[i]$,$pc[i]$为$c ...
- HDU5266 LCA 树链剖分LCA 线段树
HDU5266 LCA Description 给一棵 n 个点的树,Q 个询问 [L,R] : 求点 L , 点 L+1 , 点 L+2 -- 点 R 的 LCA. Input 多组数据. The ...
- HDU 6065 RXD, tree and sequence (LCA DP)
RXD, tree and sequence Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java ...
- 洛谷 P6071 『MdOI R1』Treequery(LCA+线段树+主席树)
题目链接 题意:给出一棵树,有边权,\(m\) 次询问,每次给出三个数 \(p,l,r\),求边集 \(\bigcap\limits_{i=l}^rE(p,i)\) 中所有边的权值和. 其中 \(E( ...
- HDU 5266 pog loves szh III
题意:给出一棵树,1为根节点,求一段区间内所有点的最近公共祖先. 解法:用一棵线段树维护区间LCA.LCA是dp做法.dp[i][j]表示点i的第2^j个祖先是谁,转移方程为dp[i][j] = dp ...
- 『MdOI R1』Treequery
我们可以思考怎么做呢. 首先我们需要进行一些分类讨论: 我们先思考一下如果所有关键点都在 \(p\) 的子树内, 那显然是所有关键点的 \(Lca\) 到 \(p\) 距离. 如果所有关键点一些在 \ ...
- 区间最深LCA
求编号在区间[l, r]之间的两两lca的深度最大值. 例题. 解:口胡几种做法.前两种基于莫队,第三种是启发式合并 + 扫描线,第四种是lct + 线段树. ①: 有个结论就是这个答案一定是点集中D ...
- 区间节点的lca
题目hdu5266 分析:多节点的LCA就是dfs序中最大最小两个节点的LCA.所以只要每次维持给出节点的dfs序的最大最小,然后就是两点的LCA 代码: rmq的st+lca的倍增 #include ...
- hdu5266 pog loves szh III 【LCA】【倍增】
Pog and Szh are playing games. Firstly Pog draw a tree on the paper. Here we define 1 as the root of ...
随机推荐
- sqli-labs通关教程----31~40关
第三十一关 这关一样,闭合变成(",简单测试,#号不能用 ?id=1") and ("1")=("1")--+ 第三十二关 这关会把我们的输 ...
- Java日期时间API系列30-----Jdk8中java.time包中的新的日期时间API类,减少时间精度方法性能比较和使用。
实际使用中,经常需要使用不同精确度的Date,比如保留到天 2020-04-23 00:00:00,保留到小时,保留到分钟,保留到秒等,常见的方法是通过格式化到指定精确度(比如:yyyy-MM-dd) ...
- python 进阶篇 python 的值传递
值传递和引用传递 值传递,通常就是拷贝参数的值,然后传递给函数里的新变量,这样,原变量和新变量之间互相独立,互不影响. 引用传递,通常是指把参数的引用传给新的变量,这样,原变量和新变量就会指向同一块内 ...
- 每天都在用,但你知道 Tomcat 的线程池有多努力吗?
这是why的第 45 篇原创文章.说点不一样的线程池执行策略和线程拒绝策略,探讨怎么让线程池先用完最大线程池再把任务放到队列中. 荒腔走板 大家好,我是 why,一个四川程序猿,成都好男人. 先是本号 ...
- spring-boot-lll-starter自动化框架介绍
1. spring-boot-lll-starter自动化框架介绍 1.1. 前言 舔着脸来介绍一波我刚写的自动化框架,spring-boot-lll-starter框架是经由我企业实战总结的一套,适 ...
- 萌新带你开车上p站(番外篇)
本文由“合天智汇”公众号首发,作者:萌新 前言 这道题目应该是pwnable.kr上Toddler's Bottle最难的题目了,涉及到相对比较难的堆利用的问题,所以拿出来分析. 登录 看看源程序 程 ...
- 10w+QPS 的 Redis 真的只是因为单线程和内存?360° 深入底层设计为你揭开 Redis 神秘面纱!
原文链接:10w+QPS 的 Redis 真的只是因为单线程和内存?360° 深入底层设计为你揭开 Redis 神秘面纱! 你以为 Redis 这么快仅仅因为单线程和基于内存? 那么你想得太少了,我个 ...
- java学习(第五篇)包装类
一.Integer package com.test01; public class IntegerTest01 { public static void main(String[] args) { ...
- 理解分布式一致性:Paxos协议之Cheap Paxos & Fast Paxos
理解分布式一致性:Paxos协议之Cheap Paxos & Fast Paxos Cheap Paxos Message flow: Cheap Multi-Paxos Fast Paxos ...
- Spring Boot JPA中使用@Entity和@Table
文章目录 默认实现 使用@Table自定义表格名字 在JPQL Queries中重写表格名字 Spring Boot JPA中使用@Entity和@Table 本文中我们会讲解如何在Spring Bo ...