Description
已知一棵n个节点的有根树。有m个询问。每个询问给出了一对节点的编号x和y,询问x与y的祖孙关系。
Input
输入第一行包括一个整数n表示节点个数。
接下来n行每行一对整数对a和b表示a和b之间有连边。如果b是-1,那么a就是树的根。
第n+2行是一个整数m表示询问个数。
接下来m行,每行两个正整数x和y。
Output
对于每一个询问,输出1:如果x是y的祖先,输出2:如果y是x的祖先,否则输出0。
10
234 -1
12 234
13 234
14 234
15 234
16 234
17 234
18 234
19 234
233 19
5
234 233
233 12
233 13
233 15
233 19
-
Sample Input
1
0
0
0
2
-
Sample Output
HINT
对于30%的数据,nm≤1000。
对于100%的.据nm≤40000,每个节点的编号都不超过40000。
应该也是LCA......
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#define SIZE 40010
using namespace std;
struct qedge
{
int to, id;
};
map<int, int> mp;
vector<qedge> qgraph[SIZE];
vector<int> graph[SIZE];
int pre[SIZE], indegree[SIZE], lca[SIZE], qx[SIZE], qy[SIZE], cnt;
bool visited[SIZE];
int find(int x) // 找祖先
{
return (pre[x] != x) ? pre[x] = find(pre[x]) : x;
}
void tarjan(int u, int pr) // 找LCA
{
int i, v;
for (i = 0; i < graph[u].size(); ++i)
{
v = graph[u][i];
if (v == pr)
{
continue;
}
tarjan(v, u);
pre[v] = u;
}
visited[u] = true;
for (i = 0; i < qgraph[u].size(); ++i)
{
v = qgraph[u][i].to;
if (visited[v])
{
lca[qgraph[u][i].id] = find(v);
}
}
return;
}
int getnumber(void) // 全部变成1~n之间的数
{
int x;
scanf("%d", &x);
if (x == -1)
{
return -1;
}
if (mp[x] > 0)
{
return mp[x]; // 一个map辅助
}
return mp[x] = ++cnt;
}
int main(void)
{
int n, m, x, y, i, root;
scanf("%d", &n);
for (i = 1; i <= n; ++i)
{
pre[i] = i;
x = getnumber(); // 建图
y = getnumber();
if (y == -1)
{
root = x;
}
else
{
graph[x].push_back(y);
graph[y].push_back(x);
}
}
scanf("%d", &m);
for (i = 1; i <= m; ++i)
{
qx[i] = getnumber(); // 询问
qy[i] = getnumber();
qgraph[qx[i]].push_back({qy[i], i});
qgraph[qy[i]].push_back({qx[i], i});
}
tarjan(root, -1); // 求LCA
for (i = 1; i <= m; ++i)
{
if (lca[i] == qx[i]) // 按照不同情况输出
{
printf("1\n");
}
else if (lca[i] == qy[i])
{
printf("2\n");
}
else
{
printf("0\n");
}
}
return 0;
}