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