【金牌导航】【点分治】树上问题

【金牌导航】【点分治】树上问题

题目

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


解题思路

点分治
重心:设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]=
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值