【洛谷】【lca+结论】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”。

输入样例#15 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
输入输出样例

 

 

【算法分析:】

对于四个点a, b, c, d,判断a->b, c->d这两条路径是否有重合的点,

容易想到分别求出(a, b), (c, d)的最近公共祖先,只要其中一个点对的lca在另一个点对的最短路径上,则这两条路径相交.

那如何判断lca与路径的位置关系呢?

首先想到树上差分,但每次O(n)维护一个前缀和肯定会超时,弃掉.

我们通过模拟可以得出这样的结论

 若一个点x在路径s->t上,则:

  1.   deep[x] ≥ deep[lca(s, t)]
  2.   lca(x, s) = x 或 lca(x, t) = x

对于结论1.,由于x可以是lca(a, b)和lca(c, d)中的任意一个,所以自然是选择深度大的lca作为x

对于结论2.,选定了x之后只需两个判断即可.

 

【代码:】

 

 1 //仓鼠找sugar
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 using namespace std;
 6 
 7 const int MAXN = 100000 + 1;
 8 const int K = 17 + 1;
 9 
10 int n, Q;
11 int deep[MAXN], f[MAXN][K];
12 int edge_num, head[MAXN];
13 struct Edge {
14     int to, nxt;
15 }h[MAXN << 1];
16 
17 inline int read() {
18     int x = 0, f = 1; char ch = getchar();
19     while(ch<'0' || ch>'9') {
20         if(ch == '-') f = -1;
21         ch = getchar();
22     }
23     while(ch>='0' && ch<='9')
24         x = (x<<3) + (x<<1) + ch-48, ch = getchar();
25     return x * f;
26 }
27 
28 inline void Add(int from, int to) {
29     h[++edge_num].to = to;
30     h[edge_num].nxt = head[from];
31     head[from] = edge_num;
32 }
33 
34 inline void build(int u) {
35     for(int i=head[u]; i!=-1; i=h[i].nxt) {
36         if(!deep[h[i].to]) {
37             deep[h[i].to] = deep[u] + 1;
38             f[h[i].to][0] = u;
39             build(h[i].to);
40         }
41     }
42 }
43 
44 inline void fill() {
45     for(int j=1; j<K; ++j)
46     for(int i=1; i<=n; ++i)
47         f[i][j] = f[f[i][j - 1]][j - 1];
48 }
49 
50 inline int LCA(int a, int b) {
51     if(deep[a] > deep[b]) swap(a, b);
52     for(int i=K-1; i>=0; --i)
53         if(deep[f[b][i]] >= deep[a]) b = f[b][i];
54     if(a == b) return a;
55     for(int i=K-1; i>=0; --i)
56         if(f[a][i] != f[b][i])
57             a = f[a][i], b = f[b][i];
58     return f[b][0];
59 }
60 
61 int main() {
62     memset(head, -1, sizeof(head));
63     n = read(), Q = read();
64     for(int i=1; i<n; ++i) {
65         int x = read(), y = read();
66         Add(x, y), Add(y, x);
67     }
68     deep[1] = 1;
69     build(1);
70     fill();
71     while(Q--) {
72         int a = read(), b = read(), c = read(), d = read();
73         int lca1 = LCA(a, b), lca2 = LCA(c, d);
74         if(deep[lca1] > deep[lca2]) {
75             swap(a, c); swap(b, d);
76             swap(lca1, lca2);
77         }
78         if(LCA(lca2, a) == lca2 || LCA(lca2, b) == lca2) puts("Y");
79         else puts("N");
80     }
81 }

 

posted @ 2018-05-17 19:05  DEVILK  阅读(214)  评论(0编辑  收藏  举报