【洛谷P3398】仓鼠找sugar

画个图就能多少看出些规律

证明借鉴一下大牛的题解:

设从A到B,经过的深度最小的点为X 同理,C,D的为Y

题目是一个点从A出发到B 一个从C出发到D

那么从A到B可以分解成 先从A到X 再从X到B。。。 C同理

假设能相遇 那么

要么在A到X的过程A,B相遇 要么在X到B的过程A,B相遇

对于在A到X的过程相遇的情况 又可以分解为:

情况1:

在A到X的过程和 C到Y的过程 中A,B相遇 此时相遇点的深度必然大于等于MIN(X深度,Y深度)

情况2:

在A到X的过程和 Y到D的过程 中A,B相遇 此时相遇点的深度必然大于等于MIN (X深度,Y深度)

另一种情况同理。。。

所以显然只要求出MIN=min(lca(a,b),lca(c,d));(lca返回的是两个点公共祖先的最大深度)

假如lca(a,c) lca(a,d) lca(b,c) lca(b,d) 中有任意一个大于等于MIN 的话 那么可以相遇 否则不能

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=100010,M=200010,p=20;
 6 int n,q,size,father[N][p+10],head[M];
 7 int nxt[M],son[M],deep[N];
 8 int read(){
 9     int sum=0;
10     char ch=getchar();
11     while (ch<‘0‘||ch>‘9‘)
12         ch=getchar();
13     while (ch>=‘0‘&&ch<=‘9‘){
14         sum=sum*10+ch-‘0‘;
15         ch=getchar();
16     }
17     return sum;
18 }
19 void uni(int x,int y){
20     size++;
21     nxt[size]=head[x];
22     head[x]=size;
23     son[size]=y;
24 }
25 void swap(int &a,int &b){
26     int tmp=a;
27     a=b;
28     b=tmp;
29 }
30 void dfs(int fa,int x){
31     for (int k=head[x];k;k=nxt[k]){
32         int y=son[k];
33         if (y==fa)
34             continue;
35         father[y][0]=x;
36         deep[y]=deep[x]+1;
37         dfs(x,y);
38     }
39 }
40 void pre(){
41     for (int j=1;j<=p;j++)
42         for (int i=1;i<=n;i++)
43             father[i][j]=father[father[i][j-1]][j-1];
44 }
45 int LCA(int x,int y){
46     if (deep[x]<deep[y])
47         swap(x,y);
48     int d=deep[x]-deep[y];
49     for (int j=p;j>=0;j--)
50         if (d&(1<<j))
51             x=father[x][j];
52     if (x==y)
53         return x;
54     for (int j=p;j>=0;j--)
55         if (father[x][j]!=father[y][j]){
56             x=father[x][j];
57             y=father[y][j];
58         }
59     return father[x][0];
60 }
61 int main(){
62     int u,v;
63     size=0;
64     n=read();
65     q=read();
66     for (int i=1;i<n;i++){
67         u=read();
68         v=read();
69         uni(u,v);
70         uni(v,u);
71     }
72     deep[1]=1;
73     for (int i=1;i<=n;i++)
74         father[i][0]=i;
75     dfs(1,1);
76     pre();
77     int a,b,c,d;
78     for (int i=1;i<=q;i++){
79         a=read();
80         b=read();
81         c=read();
82         d=read();
83         int lca=max(deep[LCA(a,b)],deep[LCA(c,d)]);
84         int l1=max(deep[LCA(a,c)],deep[LCA(a,d)]);
85         int l2=max(deep[LCA(b,c)],deep[LCA(b,d)]);
86         if (max(l1,l2)>=lca)
87             printf("Y\n");
88         else
89             printf("N\n");
90     }
91     return 0;
92 }

当然我们也可以判断一下最深的LCA是否在较浅的LCA路径之外

(比如lca_min=lca(a,b),则若deep[a]<lca_max&&deep[b]<lca_max(=lca(c,d))就在外面)

在外面肯定不能相遇

否则再判断一下它是否在其路径上

判断方法,,倍增跳点即可

  1 #include<cstdio>
  2 #include<cstring>
  3 using namespace std;
  4 const int N=100010,M=200010,p=20;
  5 int n,q,size,father[N][p+10],head[M];
  6 int nxt[M],son[M],deep[N];
  7 int read(){
  8     int sum=0;
  9     char ch=getchar();
 10     while (ch<‘0‘||ch>‘9‘)
 11         ch=getchar();
 12     while (ch>=‘0‘&&ch<=‘9‘){
 13         sum=sum*10+ch-‘0‘;
 14         ch=getchar();
 15     }
 16     return sum;
 17 }
 18 void uni(int x,int y){
 19     size++;
 20     nxt[size]=head[x];
 21     head[x]=size;
 22     son[size]=y;
 23 }
 24 void swap(int &a,int &b){
 25     int tmp=a;
 26     a=b;
 27     b=tmp;
 28 }
 29 void dfs(int fa,int x){
 30     for (int k=head[x];k;k=nxt[k]){
 31         int y=son[k];
 32         if (y==fa)
 33             continue;
 34         father[y][0]=x;
 35         deep[y]=deep[x]+1;
 36         dfs(x,y);
 37     }
 38 }
 39 void pre(){
 40     for (int j=1;j<=p;j++)
 41         for (int i=1;i<=n;i++)
 42             father[i][j]=father[father[i][j-1]][j-1];
 43 }
 44 int LCA(int x,int y){
 45     if (deep[x]<deep[y])
 46         swap(x,y);
 47     int d=deep[x]-deep[y];
 48     for (int j=p;j>=0;j--)
 49         if (d&(1<<j))
 50             x=father[x][j];
 51     if (x==y)
 52         return x;
 53     for (int j=p;j>=0;j--)
 54         if (father[x][j]!=father[y][j]){
 55             x=father[x][j];
 56             y=father[y][j];
 57         }
 58     return father[x][0];
 59 }
 60 int check(int x,int y){
 61     for (int j=p;j>=0;j--)
 62         if (deep[father[x][j]]>=deep[y])
 63             x=father[x][j];
 64     if (x==y)
 65         return 1;
 66     return 0;
 67 }//deep[x]>deep[y]
 68 int main(){
 69     int u,v;
 70     size=0;
 71     n=read();
 72     q=read();
 73     for (int i=1;i<n;i++){
 74         u=read();
 75         v=read();
 76         uni(u,v);
 77         uni(v,u);
 78     }
 79     deep[1]=1;
 80     father[1][0]=1;
 81     dfs(0,1);
 82     pre();
 83     int a,b,c,d;
 84     for (int i=1;i<=q;i++){
 85         a=read();
 86         b=read();
 87         c=read();
 88         d=read();
 89         int lcax=LCA(a,b);
 90         int lcay=LCA(c,d);
 91         if (deep[lcax]<deep[lcay]){
 92             swap(lcax,lcay);
 93             swap(a,c);
 94             swap(b,d);
 95         }//deep[lcax]>deep[lcay]
 96         if (check(lcax,lcay)&&(check(c,lcax)||check(d,lcax)))
 97             printf("Y\n");
 98         else
 99             printf("N\n");
100     }
101     return 0;
102 }

最后想说…………LCA的pre()函数……j 如果打错从0循环的话会很GG……

因为它会WA……不一定是RE……

时间: 2024-09-27 13:23:14

【洛谷P3398】仓鼠找sugar的相关文章

洛谷 P3398 仓鼠找sugar

P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整

洛谷P3398 仓鼠找sugar

题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整数u和v,表示节点u到节点v之

P3398 仓鼠找sugar(树链剖分)

P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整

luogu P3398 仓鼠找sugar x

P3398 仓鼠找sugar 224通过 860提交 题目提供者 fjzzq2002 标签 云端↑ 难度 提高+/省选- 时空限制 1s / 128MB 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救

【洛谷】【lca+结论】P3398 仓鼠找sugar

[题目描述:] 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! [输入格式:] 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有

luogu P3398 仓鼠找sugar

题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整数u和v,表示节点u到节点v之

洛谷10月月赛Round.1| P3398 仓鼠找sugar[LCA]

题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整数u和v,表示节点u到节点v之

P3398 仓鼠找sugar

题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行两个正整数u和v,表示节点u到节点v之

p3398 仓鼠找sugar (LCA+讨论)

分情况讨论,结果是两条路径有公共点时,深度大的LCA在另一条路径上且另一条路径的两个端点至少其中一个的与深度大的LCA的LCA为那个深度大的LCA #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int u[501000*2],v[500100*2],fir[500000+10],nxt[501000*2],cnt,dfs_clock=0,top[500010]

仓鼠找sugar(lca)

洛谷——P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d).他们都会走最短路径.现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友? 小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧! 输入输出格式 输入格式: 第一行两个正整数n和q,表示这棵树节点的个数和询问的个数. 接下来n-1行,每行