洛谷lca+结论P3398 仓鼠找sugar
Posted DEVILK
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷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”。
输入样例#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
【算法分析:】
对于四个点a, b, c, d,判断a->b, c->d这两条路径是否有重合的点,
容易想到分别求出(a, b), (c, d)的最近公共祖先,只要其中一个点对的lca在另一个点对的最短路径上,则这两条路径相交.
那如何判断lca与路径的位置关系呢?
首先想到树上差分,但每次O(n)维护一个前缀和肯定会超时,弃掉.
我们通过模拟可以得出这样的结论:
若一个点x在路径s->t上,则:
- deep[x] ≥ deep[lca(s, t)]
- 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 }
以上是关于洛谷lca+结论P3398 仓鼠找sugar的主要内容,如果未能解决你的问题,请参考以下文章