1. 程式人生 > >洛谷P3398 倉鼠找sugar

洛谷P3398 倉鼠找sugar

網上 etc 最短路徑 pan pac space nbsp -m 不能

題目描述

小倉鼠的和他的基(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

【思路】

放一個倍增法求lca的板子,然後求四邊lca。

題目是一個點從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相遇 
  情況2:
  在A到X的過程和 Y到D的過程 中A,B相遇 
  另一種情況同理。。。

以上是粘的洛谷上的 昨天在徐老大的幫助下成功理解為什麽(就是下面代碼的方法)
在X Y中取一個最大,再在lca(a,c).lca(a,d),lca(b,c),lca(b,d)這四個當中取一個最大,如果後者的深度大於等於前者,那麽可以相遇,否則不能;

我們從頭來說一下吧;
相遇的情況 a->X,c->y 相遇(可以認為 松鼠和他基友都在網上沖)
a->X,y->d 相遇(一個往上沖,一個在往下沖)
X->b,c->Y 相遇(一個往下沖 一個往上沖)
X->b,Y->d 相遇(都往下沖)
根據樹中的每一個節點的父親都是唯一的,lca可以認為是他們最短路徑上深度最淺的那個點,a,b,c,d到他們lca的路徑是唯一的。
而上述的4個lca中深度最大的那一個 我們姑且記為S,那麽S一定是a,b中的一個(有a無b,有b無a,我們假設是①)和c,d的一個(有c無d 有d無c,我們假設是②)的lca(仔細理解哦)
那麽如果s的深度大於x,y中較大的的那一個,說明①在和②在往上沖的過程中一定要經過他們的lca,也就是S,再經過x或者是y。因為①和②是 a,b中的一個和c,d中的一個,他們還要沖向x或者是y呢。這種情況必然相遇;
還有徐老大給我講的她看的題解。
(1)第一種特別明顯的不會有路徑相交的情況是,最深的那個lca比淺的lca的那兩個點還深,就一定不會用路徑交集。
(2)有路徑交集的情況在淺的lca的路徑一定覆蓋深的lca的路徑,那麽深的lca這個點的一定在淺的Lca的子樹裏,那麽
假如淺的Lca和深的lca的那兩個點的lca是淺的的這個點本身,那麽路徑一定有交集。。。。。。

【題解】

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 using namespace std;
 5 #define N 100009
 6 vector<int>vec[N];
 7 int n,q,u,v,a,b,c,d;
 8 int dad[N][22],depth[N];
 9 int read()
10 {
11     int x=0,f=1;
12     char ch=getchar();
13     while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
14     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}//是&&
15     return f*x;
16 }
17 void dfs(int x)
18 {
19     depth[x]=depth[dad[x][0]]+1;    
20     for(int i=0;dad[x][i];i++)//先進行這一步
21     {
22         dad[x][i+1]=dad[dad[x][i]][i];
23     }
24     for(int i=0;i<vec[x].size();i++)
25     {
26         if(!depth[vec[x][i]])
27         {
28          dad[vec[x][i]][0]=x;
29          dfs(vec[x][i]);    
30         }
31     }
32 }
33 int lca(int x,int y)
34 {
35     if(depth[x]>depth[y])
36     swap(x,y);
37     for(int i=20;i>=0;i--)
38     {
39         if(depth[dad[y][i]]>=depth[x])//到相同的深度
40         {
41             y=dad[y][i];
42         }
43     }
44     if(x==y)return x;
45     for(int i=20;i>=0;i--)
46     {
47         if(depth[dad[x][i]]!=depth[dad[y][i]])
48         x=dad[x][i],y=dad[y][i];
49     }
50     return dad[x][0];
51 }
52 int main()
53 {
54     n=read();q=read();
55     for(int i=1;i<=n-1;i++)
56     {
57         u=read();v=read();
58         vec[u].push_back(v);
59         vec[v].push_back(u);
60     }
61     dfs(1);
62     for(int i=1;i<=q;i++)
63     {
64         a=read();b=read();c=read();d=read();
65         int tep=max(depth[lca(a,b)],depth[lca(c,d)]);
66         int res=max(max(depth[lca(a,c)],depth[lca(a,d)]),
67                 max(depth[lca(b,c)],depth[lca(b,d)]));
68         if(res>=tep)
69         printf("Y\n");
70         else
71     printf("N\n");
72     }
73     return 0;
74 }

洛谷P3398 倉鼠找sugar