LCA入门题集小结
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题目:
How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21500 Accepted Submission(s): 8471
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
#include <cstdio>
#include <vector>
using namespace std; const int maxn = 4e4 + ;
int n, m, u, v, k;
int fa[maxn][], deep[maxn], cost[maxn]; struct edge {
int v, l;
edge(int v = , int l = ) : v(v), l(l) {}
}; vector<edge> G[maxn]; void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if(v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i <= n; i++) {
for(int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i <= n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << (k + )) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
G[i].clear();
}
for(int i = ; i < n; i++) {
scanf("%d%d%d", &u, &v, &k);
G[u].push_back(edge(v, k));
G[v].push_back(edge(u, k));
}
dfs(, , -);
lca();
while(m--) {
scanf("%d%d", &u, &v);
printf("%d\n", cost[u] + cost[v] - * cost[query(u, v)]);
}
}
return ;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874
题目:
Connections between cities
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13879 Accepted Submission(s): 3159
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.
| Time Limit: 2000MS | Memory Limit: 30000K | |
| Total Submissions: 15827 | Accepted: 5576 | |
| Case Time Limit: 1000MS | ||
Description
Input
* Line 2+M: A single integer, K. 1 <= K <= 10,000
* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.
Output
Sample Input
7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6
Sample Output
13
3
36
Hint
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn = 1e5 + ;
int n, m, q, u, v, k;
int fa[maxn][], deep[maxn], cost[maxn]; struct edge {
int v, l;
edge(int v = , int l = ) : v(v), l(l) {}
}; vector<edge> G[maxn]; void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if(v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i <= n; i++) {
for(int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i <= n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << ( + k)) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
while(~scanf("%d%d", &n, &m)) {
memset(cost, , sizeof(cost));
for(int i = ; i <= n; i++) {
G[i].clear();
}
for(int i = ; i < m; i++) {
scanf("%d%d%d%*s", &u, &v, &k);
G[u].push_back(edge(v, k));
G[v].push_back(edge(u, k));
}
dfs(, , -);
lca();
scanf("%d", &q);
while(q--) {
scanf("%d%d", &u, &v);
printf("%d\n", cost[u] + cost[v] - * cost[query(u, v)]);
}
}
return ;
}
题目链接:http://poj.org/problem?id=1330
题目:
| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 32969 | Accepted: 16750 |
Description

In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
Output
Sample Input
2
16
1 14
8 5
10 16
5 9
4 6
8 4
4 10
1 13
6 15
10 11
6 7
10 2
16 3
8 1
16 12
16 7
5
2 3
3 4
3 1
1 5
3 5
Sample Output
4
3 思路:裸的LCA,不过要注意它的节点之间是有向的,所以需要用一个数组来储存入度,以入度为0的节点做根节点。
代码实现如下:
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn = 1e4 + ;
int t, n, u, v, s;
int deep[maxn], fa[maxn][], in[maxn]; vector<int> G[maxn]; void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i];
if(v != p) {
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i <= n; i++) {
for(int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i <= n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << ( + k)) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
for(int i = ; i <= n; i++) {
G[i].clear();
}
memset(in, , sizeof(in));
for(int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
in[v]++;
}
for(int i = ; i <= n; i++) {
if(in[i] == ) {
s = i;
break;
}
}
dfs(s, , -);
lca();
scanf("%d%d", &u, &v);
printf("%d\n", query(u, v));
}
return ;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547
题目:
CD操作
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 3035 Accepted Submission(s): 848
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; const int maxn = 1e5 + ;
int t, n, m, cnt;
string s1, s2;
int cost[maxn], deep[maxn], fa[maxn][], in[maxn]; struct edge {
int v, l;
edge (int v = , int l = ) : v (v), l (l) {}
}; vector<edge> G[maxn];
map<string, int> mp; void init() {
cnt = ;
mp.clear();
memset (in, , sizeof (in) );
memset (cost, , sizeof (cost) );
for (int i = ; i <= n; i++) {
G[i].clear();
}
} void dfs (int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for (int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if (v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs (v, d + , u);
}
}
} void lca() {
for (int i = ; i <= n; i++) {
for (int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for (int j = ; ( << j) <= n; j++) {
for (int i = ; i <= n; i++) {
if (fa[i][j - ] != -) {
fa[i][j] = fa[fa[i][j - ]][j - ];
}
}
}
} int query (int u, int v) {
if (deep[u] < deep[v])
swap (u, v);
int k;
for (k = ; ( << ( + k) ) <= deep[u]; k++);
for (int i = k; i >= ; i--) {
if (deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if (u == v)
return u;
for (int i = k; i >= ; i--) {
if (fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
ios::sync_with_stdio (false);
cin.tie ();
cin >> t;
while (t--) {
cin >> n >> m;
init();
for (int i = ; i < n; i++) {
cin >> s1 >> s2;
if(mp.find(s1) == mp.end())
mp[s1] = ++cnt;
if(mp.find(s2) == mp.end())
mp[s2] = ++cnt;
in[mp[s1]]++;
G[mp[s1]].push_back (edge (mp[s2], ) );
G[mp[s2]].push_back (edge (mp[s1], ) );
}
int s;
for (int i = ; i <= n; i++) {
if (in[i] == ) {
s = i;
}
}
dfs (s, , -);
lca();
while (m--) {
cin >> s1 >> s2;
if(query(mp[s1], mp[s2]) == mp[s2]) {
cout <<cost[mp[s1]] - cost[mp[s2]] <<endl;
} else {
cout << cost[mp[s1]] - cost[query (mp[s1], mp[s2])] + << endl;
}
}
}
return ;
}
Time Limit: 1 Second Memory Limit: 32768 KB
Cerror is the mayor of city HangZhou. As you may know, the traffic system of this city is so terrible, that there are traffic jams everywhere. Now, Cerror finds out that the main reason of them is the poor design of the roads distribution, and he want to change this situation.
In order to achieve this project, he divide the city up to N regions which can be viewed as separate points. He thinks that the best design is the one that connect all region with shortest road, and he is asking you to check some of his designs.
Now, he gives you an acyclic graph representing his road design, you need to find out the shortest path to connect some group of three regions.
Input
The input contains multiple test cases! In each case, the first line contian a interger N (1 < N < 50000), indicating the number of regions, which are indexed from 0 to N-1. In each of the following N-1 lines, there are three interger Ai, Bi, Li (1 < Li < 100) indicating there's a road with length Li between region Ai and region Bi. Then an interger Q (1 < Q < 70000), the number of group of regions you need to check. Then in each of the following Q lines, there are three interger Xi, Yi, Zi, indicating the indices of the three regions to be checked.
Process to the end of file.
Output
Q lines for each test case. In each line output an interger indicating the minimum length of path to connect the three regions.
Output a blank line between each test cases.
Sample Input
4
0 1 1
0 2 1
0 3 1
2
1 2 3
0 1 2
5
0 1 1
0 2 1
1 3 1
1 4 1
2
0 1 2
1 0 3
Sample Output
3
2 2
2
思路:将所给的x,y,z分别两两求一次lca,然后除2即可。
代码实现如下:
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn = 5e4 + ;
int n, q, u, v, k;
int cost[maxn], deep[maxn], fa[maxn][]; struct edge {
int v, l;
edge(int v = , int l = ) : v(v), l(l) {}
}; vector<edge> G[maxn]; void init() {
memset(cost, , sizeof(cost));
for(int i = ; i < maxn; i++) {
G[i].clear();
}
} void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if(v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i < n; i++) {
for(int j = ; ( << j) < n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) < n; j++) {
for(int i = ; i < n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << k) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
int flag = ;
while(~scanf("%d", &n)) {
if(flag) printf("\n");
flag = ;
init();
for(int i = ; i < n; i++) {
scanf("%d%d%d", &u, &v, &k);
G[u].push_back(edge(v, k));
G[v].push_back(edge(u, k));
}
dfs(, , -);
lca();
scanf("%d", &q);
while(q--) {
scanf("%d%d%d", &u, &v, &k);
printf("%d\n", (cost[u] + cost[v] - * cost[query(u, v)] + cost[u] + cost[k] - * cost[query(u, k)] + cost[v] + cost[k] - * cost[query(v, k)]) / );
}
}
return ;
}
至此感觉自己的LCA应该算是入门了,深入刷难题暑假再开始,毕竟现在要开始准备期末了,免得上学期专业课满绩点,高代全年级第一,这学期全部挂科然后挨骂Σ( ° △ °|||)︴
LCA入门题集小结的更多相关文章
- poj 1330(RMQ&LCA入门题)
传送门:Problem 1330 https://www.cnblogs.com/violet-acmer/p/9686774.html 参考资料: http://dongxicheng.org/st ...
- POJ1330(LCA入门题)
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 23388 Accept ...
- lca入门———树上倍增法(博文内含例题)
倍增求LCA: father[i][j]表示节点i往上跳2^j次后的节点 可以转移为 father[i][j]=father[father[i][j-1]][j-1] 整体思路: 先比较两个点的深度, ...
- poj 2524:Ubiquitous Religions(并查集,入门题)
Ubiquitous Religions Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 23997 Accepted: ...
- hrbustoj 1073:病毒(并查集,入门题)
病毒Time Limit: 1000 MS Memory Limit: 65536 KTotal Submit: 719(185 users) Total Accepted: 247(163 user ...
- ACM题集以及各种总结大全(转)
ACM题集以及各种总结大全! 虽然退役了,但是整理一下,供小弟小妹们以后切题方便一些,但由于近来考试太多,顾退役总结延迟一段时间再写!先写一下各种分类和题集,欢迎各位大牛路过指正. 一.ACM入门 关 ...
- ACM题集以及各种总结大全!
ACM题集以及各种总结大全! 虽然退役了,但是整理一下,供小弟小妹们以后切题方便一些,但由于近来考试太多,顾退役总结延迟一段时间再写!先写一下各种分类和题集,欢迎各位大牛路过指正. 一.ACM入门 关 ...
- Codevs 3287 货车运输 2013年NOIP全国联赛提高组(带权LCA+并查集+最大生成树)
3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description A 国有 n 座 ...
- 数位dp题集
题集见大佬博客 不要62 入门题,检验刚才自己有没有看懂 注意一些细节. 的确挺套路的 #include<bits/stdc++.h> #define REP(i, a, b) for(r ...
随机推荐
- lintcode-153-数字组合 II
153-数字组合 II 给出一组候选数字(C)和目标数字(T),找出C中所有的组合,使组合中数字的和为T.C中每个数字在每个组合中只能使用一次. 注意事项 所有的数字(包括目标数字)均为正整数. 元素 ...
- 3dContactPointAnnotationTool开发日志(二)
今天看的时候发现其实www的方式是可以根据指定路径读取本地图片到Image中的.也就是昨天提到的第二种方式. 随便选了个图片做示范: 修改后的代码如下: using System.Collec ...
- SpringData——HelloWorld
1.背景 最开始了解SpringData的时候,以为他不就是ORM的一种实现方式嘛,还能有什么新的东西.从hibernate到ibatis.mybatis,也许他只不过是spring想整合一个更方便的 ...
- 【log4net】- 非常完善的Log4net详细说明
1.概述 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是介绍如何在Visual S ...
- == 和equal的区别?-005
1,== 和equal的区别? ==比较两个值是否相等,equal比较对对象的引用是否一致 举例: int a = 2; int b = 2; System.err.println(a == b);/ ...
- asp.netMVC中实现分页方法
方法一:使用传统的sql语句实现分页, public class UserprintDao如下 /// <summary> /// 取得用户申请记录列表(按分页) /// </ ...
- BZOJ 1791 岛屿(环套树+单调队列DP)
题目实际上是求环套树森林中每个环套树的直径. 对于环套树的直径,可以先找到这个环套树上面的环.然后把环上的每一点都到达的外向树上的最远距离作为这个点的权值. 那么直径一定就是从环上的某个点开始,某个点 ...
- BZOJ 1202 狡猾的商人(带权并查集)
给出了l,r,w.我们就得知了s[r]-s[l-1]=w.也就是说,点l-1和点r的距离为w. 于是可以使用带权并查集,定义dis[i]表示点i到根节点的距离.查询和合并的时候维护一下就OK了. 如果 ...
- openstack之keystone部署
前言 openstack更新频率是挺快的,每六个月更新一次(命名是是以A-Z的方式,Austin,Bexar...Newton).博主建议大家先可一种版本研究,等某一版本研究透彻了,在去研究新的版本. ...
- hdu 2962 Trucking (最短路径)
Trucking Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...