P3398 仓鼠找sugar
题目描述
小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?
小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!
输入格式
第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。
接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。
接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。
输出格式
对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。
输入输出样例
输入 #1
5 5 2 5 4 2 1 3 1 4 5 1 5 1 2 2 1 4 4 1 3 4 3 1 1 5 3 5 1 4
输出 #1
Y N Y Y Y
说明/提示
__本题时限1s,内存限制128M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。__
20%的数据 n<=200,q<=200
40%的数据 n<=2000,q<=2000
70%的数据 n<=50000,q<=50000
100%的数据 n<=100000,q<=100000
#include<bits/stdc++.h> using namespace std; const int SIZE = 2e5 + 7; int f[SIZE][20], d[SIZE]; int ver[SIZE], nex[SIZE], head[SIZE]; int n, m, tot, t; void add(int x, int y) { ver[++tot] = y; nex[tot] = head[x]; head[x] = tot; } int q[SIZE]; void bfs() { int l = 0, r = 0; q[r++] = 1; d[1] = 1; while (l < r) { int x = q[l++]; for (int i = head[x]; i; i = nex[i]) { int y = ver[i]; if (d[y]) continue; 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[r++] = 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]; } int dis(int a, int b) { int fa = lca(a, b); return abs(d[fa] - d[a]) + abs(d[fa] - d[b]); } void solve() { int x, y, s, c; cin >> n >> m; t = log(n) / log(2) + 1; for (int i = 1; i < n; i++) { scanf("%d%d", &x, &y); add(x, y); add(y, x); } bfs(); while (m--) { scanf("%d%d%d%d", &x, &y, &s, &c); int f1 = lca(x, y), f2 = lca(s, c);
// 如果f2在x,y的路径上,则dis(x, f2) + dis(y, f2) = dis(x, y) if (dis(x, f2) + dis(y, f2) == dis(x, y) || dis(s, f1) + dis(c, f1) == dis(s, c)) printf("Y\n"); else printf("N\n"); } } int main() { solve(); return 0; }

浙公网安备 33010602011771号