题目大意:

给一棵有 n 个顶点的树,每条边都有一个长度(小于 1001 的正整数)。
定义 dist(u,v)=节点 u 和 v 之间的最小距离。
给定一个整数 k,对于每一对 (u,v) 顶点当且仅当 dist(u,v) 不超过 k 时才称为有效。
编写一个程序,计算给定树有多少对有效。

算法分析:

这道题是一道标准的点分治模板题。题目给定的树是一颗无根树,我们首先选取点作为根节点,这里选取树的重心root作为划分点,使得将树划分得尽量均衡。然后我们统计每个点到根节点的距离,将这些距离加入到一个距离数组中,排序,用双指针扫描,就可以统计以root为根的满足条件的节点数,这里还要用到容斥的思想,我们对root的子树v都要减去重复统计的节点数,从v出发重复以上的过程。

要算两个节点之间的最小距离不超过k,以root为根,则有两种情况:

1.两个点在以root为根的同一颗子树中;

2.两个点在不同子树中;

  1 #include<cstdio>
2 #include<cstring>
3 #include<algorithm>
4 using namespace std;
5 const int maxn=10005;
6 int cnt,n,k,ans,head[maxn];
7 int root,S,size[maxn],f[maxn],d[maxn],dep[maxn];
8 bool vis[maxn];
9 struct edge
10 {
11 int to,next,w;
12 }edge[maxn*2];
13
14 void add(int u,int v,int w)
15 {
16 edge[++cnt].to=v;
17 edge[cnt].w=w;
18 edge[cnt].next=head[u];
19 head[u]=cnt;
20 }
21
22 void getroot(int u,int fa)//获取重心
23 {
24 size[u]=1;
25 f[u]=0;//删除u后,最大子树的大小
26 for(int i=head[u];i;i=edge[i].next)
27 {
28 int v=edge[i].to;
29 if(v!=fa&&!vis[v])
30 {
31 getroot(v,u);
32 size[u]+=size[v];
33 f[u]=max(f[u],size[v]);
34 }
35 }
36 f[u]=max(f[u],S-size[u]);//S为当前子树总结点数
37 if(f[u]<f[root])
38 root=u;
39 }
40
41 void getdep(int u,int fa)//获取距离
42 {
43 dep[++dep[0]]=d[u];//保存距离数组
44 for(int i=head[u];i;i=edge[i].next)
45 {
46 int v=edge[i].to;
47 if(v!=fa&&!vis[v])
48 {
49 d[v]=d[u]+edge[i].w;
50 getdep(v,u);
51 }
52 }
53 }
54
55 int getsum(int u,int dis) //获取u的子树中满足个数
56 {
57 d[u]=dis;
58 dep[0]=0;
59 getdep(u,0);
60 sort(dep+1,dep+1+dep[0]);
61 int L=1,R=dep[0],sum=0;
62 while(L<R)
63 if(dep[L]+dep[R]<=k)
64 sum+=R-L,L++;
65 else
66 R--;
67 return sum;
68 }
69
70 void solve(int u) //获取答案
71 {
72 vis[u]=true;
73 ans+=getsum(u,0);
74 for(int i=head[u];i;i=edge[i].next)
75 {
76 int v=edge[i].to;
77 if(!vis[v])
78 {
79 ans-=getsum(v,edge[i].w);//减去重复
80 root=0;
81 S=size[v];
82 getroot(v,u);
83 solve(root);
84 }
85 }
86 }
87
88 int main()
89 {
90 f[0]=0x7fffffff;//初始化树根
91 while(scanf("%d%d",&n,&k),n+k)
92 {
93 memset(vis,0,sizeof(vis));
94 memset(head,0,sizeof(head));
95 cnt=0;ans=0;
96 for(int i=1;i<=n-1;i++)
97 {
98 int x,y,z;
99 scanf("%d%d%d",&x,&y,&z);
100 add(x,y,z);
101 add(y,x,z);
102 }
103 root=0;
104 S=n;
105 getroot(1,0);
106 solve(root);
107 printf("%d\n",ans);
108 }
109 return 0;
110 }

每次选取重心作为划分点,点分治最多递归O(logn)层,距离数组排序O(nlogn),总的时间复杂度O(n)。

POJ1741 tree (点分治模板)的更多相关文章

  1. POJ1741 Tree 树分治模板

    http://poj.org/problem?id=1741   题意:一棵n个点的树,每条边有距离v,求该树中距离小于等于k的点的对数.   dis[y]表示点y到根x的距离,v代表根到子树根的距离 ...

  2. [poj1741]Tree(点分治+容斥原理)

    题意:求树中点对距离<=k的无序点对个数. 解题关键:树上点分治,这个分治并没有传统分治的合并过程,只是分成各个小问题,并将各个小问题的答案相加即可,也就是每层的复杂度并不在合并的过程,是在每层 ...

  3. POJ - 1741 - Tree - 点分治 模板

    POJ-1741 题意: 对于带权的一棵树,求树中距离不超过k的点的对数. 思路: 点分治的裸题. 将这棵树分成很多小的树,分治求解. #include <algorithm> #incl ...

  4. [POJ1741]Tree(点分治)

    树分治之点分治入门 所谓点分治,就是对于树针对点的分治处理 首先找出重心以保证时间复杂度 然后递归处理所有子树 对于这道题,对于点对(u,v)满足dis(u,v)<=k,分2种情况 路径过当前根 ...

  5. [bzoj1468][poj1741]Tree[点分治]

    可以说是点分治第一题,之前那道的点分治只是模模糊糊,做完这道题感觉清楚了很多,点分治可以理解为每次树的重心(这样会把数分为若干棵子树,子树大小为log级别),然后统计包含重心的整个子树的值减去各个子树 ...

  6. bzoj 1468 Tree(点分治模板)

    1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1527  Solved: 818[Submit][Status][Discuss] ...

  7. [洛谷P4178] Tree (点分治模板)

    题目略了吧,就是一棵树上有多少个点对之间的距离 \(\leq k\) \(n \leq 40000\) 算法 首先有一个 \(O(n^2)\) 的做法,枚举每一个点为起点,\(dfs\) 一遍可知其它 ...

  8. POJ1741 Tree + BZOJ1468 Tree 【点分治】

    POJ1741 Tree + BZOJ1468 Tree Description Give a tree with n vertices,each edge has a length(positive ...

  9. poj1741 Tree(点分治)

    题目链接:http://poj.org/problem?id=1741 题意:求树上两点之间距离小于等于k的点对的数量 思路:点分治模板题,推荐一篇讲的非常好的博客:https://blog.csdn ...

随机推荐

  1. 面试突击68:为什么 TCP 需要 3 次握手?

    TCP 三次握手是一道经典的面试题,它是指 TCP 在传递数据之前,需要进行 3 次交互才能正式建立起连接,并进行数据传递. TCP 之所以需要 3 次握手是因为 TCP 双方都是全双工的.所谓全双工 ...

  2. WPF 截图控件之移除控件(九)「仿微信」

    WPF 截图控件之移除控件(九)「仿微信」 WPF 截图控件之移除控件(九)「仿微信」 作者:WPFDevelopersOrg 原文链接: https://github.com/WPFDevelope ...

  3. How to code like a pro in 2022 and avoid If-Else

    在浏览文章的时候发现了一篇叙述有关if-else语句的文章,这篇文章作者是Thai Tran,他原文是用英语写的,然后看着文章浅显易懂,便尝试翻译成汉语.如有不妥还望指出. 原文链接:https:// ...

  4. 架构与思维:互联网高性能Web架构

    1 什么是高性能Web架构 在互联网业务中,我们经常会面临流量巨大的复杂的分布式场景.这就要求我们在设计系统的时候保证系统具有承载高并发(High Concurrency)的能力,同时能够保证系统的高 ...

  5. PHP为任意页面设访问密码

    使用方法 把下面的代码存为php文件,下面的整段代码是验证过程,然后在你入口页进行调用例如命名为MkEncrypt.php,那么在入口页进行       require_once('MkEncrypt ...

  6. Spring(二)-生命周期 + 自动装配(xml) +自动装配(注解)

    1.生命周期 **Spring容器的 bean **的生命周期: 1.1 默认生命周期 1.1.1 生命周期 调用构造方法,创建实例对象: set方法,给实例对象赋值: init 初始化方法 初始化对 ...

  7. Math_Music

    查看代码 #REmoo的优化任务 #1.公式写在<formula_set>类中,统一管理 --- Finished 2022.8.15 12:39 #2.建立<sample_set& ...

  8. 【java】学习路线3-二维数组声明与初始化、Arrays类

    import java.util.Arrays;public class Learn02{    public static void main(String[] args){        Syst ...

  9. 【IDEA】IDEA怎么汉化&汉化后怎么转回英文

    ① 英文转中文 1.点击左上角的File,然后选择Setting 2.达到Setting页面选择Plugins 3.在搜索框搜索chinese,选择中文语言包下载 4.找到下载插件,选择勾选上,然后o ...

  10. 抛砖系列之git仓库拆分工具git-filter-repo

    最近负责把团队内的git仓库做了一次分拆,解锁一个好用的工具git-filter-repo,给大伙抛砖一波,希望以后遇到类似场景时可以信手拈来. 背景 笔者团队目前是把业务相关的java项目都放到了一 ...