CSU 1079: 树上的查询 (LCA最近公共祖先问题)
【摘要】
题目:
Description
现有一棵有N个顶点的树,顶点的标号分别为1, 2, …, N。对于每个形如a b k的询问,你需要回答在从点a到点b的路径上是否包含点k。
Input
输入包含多组测试数据。
对于每组测试数据,第一行包含两个正整数N, Q (1<=N, Q<=10^5),分别表示这棵树一共有...
题目:
Input
输入包含多组测试数据。
对于每组测试数据,第一行包含两个正整数N, Q (1<=N, Q<=10^5),分别表示这棵树一共有N个顶点,接下来你需要回答Q个询问。接下来N-1行中,第i行描述了这棵树的第i条边:包含两个正整数xi、yi,表示点xi和点yi之间有一条无向边。再接下来一共Q行,每行均包含三个正整数a、b、k (1<=a, b, k<=N),表示你需要回答在从点a到点b的路径上是否包含点k。
Output
对于每组测试数据,你需要按顺序依次回答每个询问。对于任意一个询问a b k,如果点a到点b的路径上包含点k,则输出“YES”(不包括引号),否则输出“NO”(不包括引号)。每组数据结尾输出一个空行。
就是简单的LCA问题,关于LCA参考我的另外一篇博客:HDU 2586 How far away?(LCA使用详解)
代码:
-
#include<iostream>
-
#include<stdio.h>
-
#include<vector>
-
using namespace std;
-
-
int n;
-
vector<int>v[100001];//存儿子标号
-
int deep[100001];//每个点的深度
-
int visitnum[200001];//遍历数是2*n-1
-
int visitn[100001];//每个点的任意一个遍历数
-
int vnum;
-
int mins[200001][20]; //区间最小值
-
int fa[100001];
-
-
void visit(int m, int d) //遍历重编号
-
{
-
vector<int>::iterator p;
-
deep[m] = d;
-
for (p = v[m].begin(); p != v[m].end(); p++)
-
{
-
if (fa[*p]>-1)continue;
-
fa[*p] = m;
-
visitnum[vnum++] = m; //存入访问的第vnum个点是哪个点
-
visit(*p, d + 1);
-
}
-
visitn[m] = vnum; //注意这2句的顺序
-
visitnum[vnum++] = m;
-
}
-
-
void rmq() //计算区间最小值
-
{
-
for (int i = 1; i <= 2 * n - 1; i++)mins[i][0] = visitnum[i];
-
for (int j = 1; (1 << j) <= 2 * n - 1; j++)
-
{
-
for (int i = 1; i <= 2 * n - 1; i++)
-
{
-
mins[i][j] = mins[i][j - 1];
-
int k = i + (1 << (j - 1));
-
if (k <= 2 * n - 1 && deep[mins[i][j]] > deep[mins[k][j - 1]])
-
mins[i][j] = mins[k][j - 1];
-
}
-
}
-
}
-
-
int lca(int x, int y) //求最近公共祖先
-
{
-
x = visitn[x], y = visitn[y];
-
if (x > y)x ^= y ^= x ^= y;
-
int j = 0;
-
while ((1 << j) <= y - x + 1)j++;
-
j--;
-
int min = mins[y + 1 - (1 << j)][j];
-
if (deep[min] > deep[mins[x][j]])min = mins[x][j];
-
return min;
-
}
-
-
int main()
-
{
-
int q, x, y, k;
-
bool fl = false;
-
while (scanf("%d%d", &n, &q) != EOF)
-
{
-
if (fl)printf("\n");
-
fl = true;
-
vnum = 1;
-
for (int i = 1; i <= n; i++)
-
{
-
v[i].clear(); //初始化
-
fa[i] = -1;
-
}
-
for (int i = 1; i < n; i++)
-
{
-
scanf("%d%d", &x, &y);
-
v[x].insert(v[x].end(), y);//存入儿子的标号
-
v[y].insert(v[y].end(), x);//存入儿子的标号
-
}
-
fa[1] = 1;
-
visit(1, 1);
-
rmq();
-
while (q--)
-
{
-
scanf("%d%d%d", &x, &y, &k);
-
int lca1 = lca(x, y), lca2 = lca(x, k), lca3 = lca(y, k);
-
bool flag = (lca1 == lca2 && lca3 == k);
-
if (lca1 == lca3 && lca2 == k)flag = true;
-
if (flag)printf("YES\n");
-
else printf("NO\n");
-
}
-
}
-
return 0;
-
}
文章来源: blog.csdn.net,作者:csuzhucong,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/nameofcsdn/article/details/79775935
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)