洛谷P3398仓鼠找sugar

Posted Absolutezero

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷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 }
View Code

 

当然我们也可以判断一下最深的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 }
View Code

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

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

以上是关于洛谷P3398仓鼠找sugar的主要内容,如果未能解决你的问题,请参考以下文章

洛谷 P3398 仓鼠找sugar

洛谷 [P3398] 仓鼠找sugar

洛谷P3398 仓鼠找sugar

洛谷 P3398 仓鼠找sugar

洛谷P3398 仓鼠找sugar

[洛谷 P3398] 仓鼠找sugar