二叉树
树
树的直径:最长的一条路径
树的中心:一条树的直径的中心点
树的中心的性质:是到所有到其他点路径最长的最小值,也就是直径的一半上取整
并且树的中心是唯一确定的(树的直径的长度是偶数的话唯二)
树的重心:选一个节点,当成根节点,他的儿子的子树大小最大值最小,这个节点就是重心
性质:当重心是根节点的时候,他下面每个子树的大小是不大于整棵树的一半的(反过来也是成立的,
并且可以发现如果有两个重心的,两个重心一定是连在一起的)
重心到其他所有节点的距离和是最小的
// 求树的直径
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
vector<int> sons[N];
int dist[N];
void dfs1(int u, int fa){
for(auto son : sons[u]){
if(son == fa) continue;
dist[son] = dist[u] + 1;
dfs1(son, u);
}
}
int main(){
int n; scanf("%d", &n);
for(int i = 1; i <= n - 1; i ++){
int x, y; scanf("%d %d", &x, &y);
sons[x].push_back(y);
sons[y].push_back(x);
}
dfs1(1, -1);
int lenmaxn = 0, lenid = 0;
for(int i = 1; i <= n; i ++){
if(dist[i] > lenmaxn) lenmaxn = dist[i], lenid = i;
}
dist[lenid] = 0;
dfs1(lenid, -1);
lenmaxn = 0, lenid = 0;
for(int i = 1; i <= n; i ++){
if(dist[i] > lenmaxn) lenmaxn = dist[i], lenid = i;
}
cout << lenmaxn << endl;
return 0;
}
LCA
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010;
vector<int> sons[N];
int father[N][21], dist[N];
void dfs(int u){
for(auto v : sons[u]){
dist[v] = dist[u] + 1;
dfs(v);
}
}
int main(){
int n; scanf("%d", &n);
for(int i = 1; i <= n - 1; i ++){
int x, y; scanf("%d %d", &x, &y);
sons[x].push_back(y);
father[y][0] = x;
}
for(int i = 1; i <= 20; i ++){
for(int j = 1; j <= n; j ++){
if(father[father[j][i - 1]]) father[j][i] = father[father[j][i - 1]][i - 1];
}
}
memset(dist, 0, sizeof dist);
dfs(1);
int m; scanf("%d", &m);
while(m -- ){
int x, y; scanf("%d %d", &x, &y);
if(dist[x] < dist[y]) swap(x, y);
int z = dist[x] - dist[y];
for(int j = 0; z ; z /= 2, j ++){
if(z & 1) x = father[x][j];
}
if(x == y){
printf("%d\n", x);
continue;
}
for(int j = 20; j >=0; j --){
if(father[x][j] != father[y][j]) x = father[x][j], y = father[y][j];
}
printf("%d\n", father[x][0]);
}
return 0;
}