P4281 AHOI2008 緊急集合 聚會

2022-05-05 19:54:10 字數 1405 閱讀 2113

給定一棵樹, 邊權為 \(1\), 多次詢問, 給出三個點 \(a, b, c\) 求三個點的中點和到中點的總距離

定義中點為 \(x\) 滿足 \(dis(a, x) + dis(b, x) + dis(c, x)\) 最小

除錯日誌: \(jump\) 陣列開小, 只開了 \(19\) ...

首先是樹上兩點距離:$$dis(x, y) = dep[x] + dep[y] - 2 * dep[lca(x, y)]$$

根到 \(lca\) 的距離計算了兩遍, 減去, 即可得到上式

回到這題, 發現三點兩兩 \(lca\) 中總有兩個一樣

為什麼呢? 設 \(x = lca(a, b)\) , \(lca(x, c)\) 即為重合的點, 因為此點是 \(x\) 的祖先, 必然是 \(a, b\) 的祖先

然後 找規律 可得集合點一定是三個 \(lca\) 中深度最大的那個

我呸可以發現, 深度大的那個 \(lca\) 掌管著更深的兩個點, 用反證法, 若是將集合點上移 \(d\) 對於乙個點 \(-d\) 對於另外深度大兩個點一共 \(+2d\) , 即總距離 \(+d\) , 不優

而若是將集合點下移 \(d\) , 那麼此點將不在三點的公共路線上, 必然不優

綜上可得: 集合點在三個 \(lca\) 中深度大的點

然後套距離公式, 發現化簡得如下式子$$\min dis(a, b, c) = dep[a] + dep[b] + dep[c] - dep[lca1] - dep[lca2] - dep[lca3]$$

#include#include#include#include#include#define ll long long

using namespace std;

int rd()

while(c >= '0' && c <= '9')

return flag * out;

}const int maxn = 1000019,inf = 1e9 + 19;

int head[maxn],nume = 1;

struct nodee[maxn << 3];

void add(int u,int v,int dis)

int num, na;

int dep[maxn], jump[maxn][25];

void dfs(int id, int f)

}void get_jump()

} }int lca(int x, int y)

return jump[x][0];

}int main()

dep[1] = 1;

dfs(1, -1), get_jump();

while(na--)

return 0;

}

P4281 AHOI2008 緊急集合 聚會

題意描述 link 歡樂島上有個非常好玩的遊戲,叫做 緊急集合 在島上分散有 n 個等待點,有 n 1 條道路連線著它們,每一條道路都連線某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從乙個點到另乙個點要花費乙個遊戲幣。參加遊戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上 ...

AHOI2008 緊急集合 LCA

題目大意 給一棵樹,求三點之間最短距離,並求最短距離所在的點。題解 求出兩兩之間的lca,觀察可以發現,有兩個lca是相同的,且這個點一定在所有lca中深度最淺。畫乙個圖可以發現,集合點就是另乙個lca,因為這個點是這三個點互相路徑連線起來的公共點。至於距離,找個例子可以發現距離是dep a dep...

AHOI2008 緊急集合 聚會

歡樂島上有個非常好玩的遊戲,叫做 緊急集合 在島上分散有n個等待點,有n 1條道路連線著它們,每一條道路都連線某兩個等待點,且通過這些道路可以走遍所有的等待點,通過道路從乙個點到另乙個點要花費乙個遊戲幣。參加遊戲的人三人一組,開始的時候,所有人員均任意分散在各個等待點上 每個點同時允許多個人等待 每...