題解 AHOI2008 緊急集合 聚會

2021-09-10 14:08:11 字數 2365 閱讀 3068

簡化版題目:

有一棵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條道路連線著它們,每一條道路都連線某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從乙個點到另乙個點要花費乙個遊戲幣。參加遊戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上 每個點同時允許多個人等待 每...