簡化版題目:
有一棵n
nn個節點的樹,和q
qq組詢問
有三個人分別在點x,y
,z
x,y,z
x,y,
z現在希望你找到乙個點,使得
三個人到這個點的距離和最小。
首先,本題最大的難度就是求的是三條路徑的最小值,而不是兩個,如果是兩個的話我們直接求書的路徑上的點就行,即為求兩點之間的lca
lcalc
a,但是如果問題為3
33的點就不同了,我們模擬之前,可能會想到求出3
33個點的lca
lcalc
a,可是這樣,明顯是不對的,比如下邊這幅圖就是乙個反例。
·a
/ \
/ \
/ \
.c .b
/ \/ \
.d .e
若在此圖中尋找乙個點,使其到b,e
,f
b,e,f
b,e,
f之和最小,顯然不是求三者lca
−a
lca-a
lca−
a點,而是應當選c
cc點,這樣他們的值才能最小。
為什麼這麼說呢?可以把b
bb翻轉過來,然後就可以發現應該在他們的交點c
cc上可以取到最小值。
這道題還有乙個情況如下
.a//
c./ \
/ \
.b \
d.
現在我們要求b,c
,d
b,c,d
b,c,
d的最短距離,我們怎麼走。
這其實是最簡單的一種模型。肯定是走在b
bb時最短。
然後我們發現,無論這棵樹有多麼複雜,一共就這兩種雛形的情況。
然後開始我們找規律時間
其實上述的推理得到的結論就是:找兩兩之間lca
lcalc
a深度最深的乙個
於是這個問題就這樣解決了,時間複雜度為o(n
o(no(nlo
glog
logn)n)
n)關於lca
lcalc
a,因為我太菜了,我用的是倍增求lca
lcalc
a。當然也可以用別的方法
參考**如下
#include
#include
#include
#include
#define n 500001
using
namespace std;
int n,m,id[n]
,cnt,fa[n][21
],p,deep[n]
,tmp;
int front[n]
,next[n*2]
,to[n*2]
,tot;
int lca1,lca2,lca3;
template
<
class
t>
inline
void
read
(t &x)
template
<
class
t>
inline
void
print
(t x)
void
add(
int x,
int y)
void
dfs(
int x)
}int
lca(
int x,
int y)
intdis
(int x,
int y)
intmain()
dfs(1)
; p=
log(n)
/log(2
)+1;
for(
int j=
1;j<=p;j++
)for
(int i=
1;i<=n;i++
) fa[i]
[j]=fa[fa[i]
[j-1]]
[j-1];
int ans1,ans2,tmp;
while
(m--
) tmp=
dis(x,lca3)
+dis
(y,lca3)
+dis
(z,lca3);if
(tmpprintf
("%d %d\n"
,ans1,ans2);}
}
AHOI2008 緊急集合 聚會 題解
歡樂島上有個非常好玩的遊戲,叫做 緊急集合 在島上分散有n個等待點,有n 1條道路連線著它們,每一條道路都連線某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從乙個點到另乙個點要花費乙個遊戲幣。參加遊戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上 每個點同時允許多個人等待 每...
AHOI2008 緊急集合 LCA
題目大意 給一棵樹,求三點之間最短距離,並求最短距離所在的點。題解 求出兩兩之間的lca,觀察可以發現,有兩個lca是相同的,且這個點一定在所有lca中深度最淺。畫乙個圖可以發現,集合點就是另乙個lca,因為這個點是這三個點互相路徑連線起來的公共點。至於距離,找個例子可以發現距離是dep a dep...
AHOI2008 緊急集合 聚會
歡樂島上有個非常好玩的遊戲,叫做 緊急集合 在島上分散有n個等待點,有n 1條道路連線著它們,每一條道路都連線某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從乙個點到另乙個點要花費乙個遊戲幣。參加遊戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上 每個點同時允許多個人等待 每...