Problem
Pik's village comprises of n residential buildings (labeled from 1 to n) connected by n−1 bidirectional roads. The village forms a tree structure, where each building is interpreted as a tree vertex, and each road is interpreted as a tree edge. Within the village, there are a total of m bus routes. The i-th bus route (1≤i≤m) originates from building ui and follows the shortest path on the tree to building vi, and then it reverses its path to return to building ui. When villagers wish to use the i-th bus route, they can board the bus only from either building ui or building vi. They are free to disembark at any building along the shortest path between ui and vi.
Pik, as the village chief, is curious about the minimum number of bus routes needed to reach any building within the village, starting from building 1 where he resides; print −1 if there is a building that cannot be reached.
Input
The first line contains two integers, n and m (1<n≤100000 and 1≤m≤100000 ), representing the number of buildings and bus routes, respectively. The following line consists of n−1 integers, where the i-th integer pi indicates a road connecting building pi and i+1. It is guaranteed that pi≤i for 1≤i≤n−1.
Then m lines are provided, where the i-th line consists of two integers, ui and vi (ui=vi), indicating a bus route.
Output
One line with n−1 integers, where the i-th integer represents the minimum number of buses required to reach building i+1 from building 1. Print −1 if i+1 cannot be reached.
Sample Input
10 6
1 2 1 4 4 6 7 2 9
1 4
3 6
3 7
9 4
5 10
3 4
Sample Output
2 2 1 -1 3 3 -1 2 -1
题意
有一个村子,里面的建筑物和路可以构成一棵无向树,有一个人站在1号节点,问从1号节点到任意一个节点,至少要乘坐几个公交车线路
输入 第一行给出n 和 m,表示有n个建筑,m条公交车路线。第二行给出n-1个数,代表pi节点和i+1之间有一条通路。其余m行每行两个数u和v,代表从u到v(v到u)是一条无向公交车路线,这条路走的是最短路径。可以从公交车经过任意节点下车,但是只能从起点u或v上车。
输出 有n - 1个数,代表从1到i+1需要乘坐多少个公交车路线
思路
首先在找最短路上,由于是树,两个节点的最短路径一定会经过他们的最近公共祖先,所以我们采用LCA来找最短路。对于给出的公交车起点终点,我们另建一个图采取从1开始bfs搜索。开一个数组记录到达每个节点的乘坐数量,公交车经过节点的数量等于起点+1,搜索过的记录一下,下次搜索到之间break,能优化掉大量时间(因为是个树,而且要到1,这个节点如果已经被搜索过,那么它以上的也被搜索过),同时公交车经过的节点要随时入队。
代码
#include<bits/stdc++.h>
using namespace std;
#define enl , writestr("\n")
#define int long long
#define endl "\n"
#define PII pair<int, int>
#define ULL unsigned long long
#define xx first
#define yy second
#define PI acos(-1)
const int P = 131;//131,13331
const int N = 1e6 + 10;
const int M = 1e3 + 10;
const int INF = 1e18;
const int ENF = -1e18;
const int mod = 1e9 + 7;//998244353
const int modd = 998244353;
void ClearFloat() { ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); }int read() { int ret = 0, f = 1; char ch = getchar(); while ('0' > ch || ch > '9') { if (ch == '-')f = -1; ch = getchar(); }while ('0' <= ch && ch <= '9') { ret = ret * 10 + ch - '0'; ch = getchar(); }return ret * f; }void write(int x) { char num[30]; int cnt = 0; if (x == 0) { putchar('0'); return; }if (x < 0) { putchar('-'); x = -x; }while (x > 0) { num[cnt++] = x % 10 + '0'; x /= 10; }while (cnt > 0) { putchar(num[--cnt]); } }double readdou() { double x = 0; int flag = 0; char ch = 0; while (!isdigit(ch)) { flag |= (ch == '-'); ch = getchar(); } while (isdigit(ch)) { x = x * 10 + (ch - '0'); ch = getchar(); }if (ch != '.') return flag ? -x : x; int f = 1; ch = getchar(); while (isdigit(ch)) { x = x + (ch - '0') * pow(10, -f); f++; ch = getchar(); }return flag ? -x : x; }void wridou(int x) { char num[30]; int cnt = 0; if (x == 0) { putchar('0'); return; }if (x < 0) { putchar('-'); x = -x; }while (x > 0) { num[cnt++] = x % 10 + '0'; x /= 10; }while (cnt > 0) { putchar(num[--cnt]); } }int gcd(int a, int b) { if (b) while ((a %= b) && (b %= a)); return a + b; }int lcm(int a, int b) { return a * b / gcd(a, b); }
int e[N], h[N], f[N][25], idx, ne[N], n, m, d[N], t, fat[N], res[N];//res数组为答案,fat数组记录父节点
queue<int>q;
bool st[N];
vector<int>vt[N];
void add(int a, int b)
{
e[++idx] = b, ne[idx] = h[a], h[a] = idx;
}
void bfs()
{
queue<int>q;
q.push(1); d[1] = 1;
while (q.size())
{
int x = q.front(); q.pop();
for (int i = h[x]; i; i = ne[i])
{
int y = e[i];
if (d[y]) continue;
fat[y] = x;
d[y] = d[x] + 1;
f[y][0] = x;
for (int j = 1; j <= t; j++)
{
f[y][j] = f[f[y][j - 1]][j - 1];
}
q.push(y);
}
}
}
int lca(int x, int y)
{
if (d[x] > d[y])swap(x, y);
for (int i = t; i >= 0; i--)
if (d[f[y][i]] >= d[x])y = f[y][i];
if (x == y)return x;
for (int i = t; i >= 0; i--)
{
if (f[x][i] != f[y][i])
{
x = f[x][i], y = f[y][i];
}
}
return f[x][0];
}
signed main()
{
ClearFloat();
cin >> n >> m;
t = (log(n) / log(2)) + 1;
for (int i = 2; i <= n; i++)
{
int x;
cin >> x;
add(x, i), add(i, x);
}
bfs();
for (int i = 1; i <= m; i++)//将公交车起点终点另外建图
{
int u, v;
cin >> u >> v;
vt[u].push_back(v), vt[v].push_back(u);
}
q.push(1);//从1开始搜索公交车路线
while (q.size())
{
int t = q.front();
q.pop();
st[t] = true;
for (int i = 0; i < vt[t].size(); i++)//搜索以当前点为起点的终点,并求出这条路线上的答案
{
int it = vt[t][i];//终点
if (!st[it])
{
q.push(it);//终点入队
int op = lca(t, it);//求出最近公共祖先
int a = fat[it], b = fat[t];//分别从它们的父节点开始向上搜索到1
if (!st[it]) res[it] = res[t] + 1, st[it] = true;//公交车上的点等于起点+1
while (a != 1)//两个bfs分别表示从终点和起点搜索到1,已经搜索到就break
{
if (st[a]) break;
st[a] = true;
q.push(a);
res[a] = res[t] + 1;
if (a == op) break;
a = fat[a];
}
while (b != 1)
{
if (st[b]) break;
st[b] = true;
q.push(b);
res[b] = res[t] + 1;
if (b == op) break;
b = fat[b];
}
}
}
}
for (int i = 2; i <= n; i++)
{
if (!res[i]) cout << -1 << ' ';
else cout << res[i] << ' ';
}
}