【金牌导航】【点分治】树上问题
题目
解题思路
点分治
重心:设son[x]表示以x为根的最大子树的节点数,若x为重心,当且仅当对于任意不同与x的i,son[i]>=son[x]
定理:由重心划分出来的子树大小都不大于n/2(n是树的大小)
题目要找距离不大于k的点对
用重心x把树分成若干个子树
那么符合的点对有三种情况
- 1 在同一子树内
- 2 在不同的子树内,经过重心x
- 3 与重心x组成的点对
2和3是可以合并的,d(i)表示从s到i的距离,统计d(i)+d(j)<=k的个数
同一子树内的情况会递归求解,所以要减去,再递归
代码
#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
const int inf=90000;
struct lzf{
int to,w,nxt;
}f[inf];
bool vis[inf];
int t,n,m,k,u,v,w,ans,d[inf],q[inf],fa[inf];
int dis[inf],son[inf],size[inf],head[inf];
//fa记录爸爸,son是最大子树,size是子树大小
int weight(int x) //求重心,最大子树最小的点
{
fa[x]=0;
int tot=1,mx=n,w;
q[tot]=x;
for (int j=1;j<=tot;j++)
{
int u=q[j];
son[u]=