题目大意:

给一棵有 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. Mybatis源码解读-插件

    插件允许对Mybatis的四大对象(Executor.ParameterHandler.ResultSetHandler.StatementHandler)进行拦截 问题 Mybatis插件的注册顺序 ...

  2. Command 'ifconfig' not found, but can be installed with: sudo apt install net-tools解决方法

    VMware下安装的Ubuntu 当使用ifconfig命令查看网卡配置信息的时候出错 尝试了很多方法都解决不了,直到输入了下面的内容: 然后自己就更新了很多东西 之后重新输入ifconfig命令就能 ...

  3. javascript的原型链那些事

    如果你对javascript的原型链还有任何疑问,请看这篇文章 进入主题 前言 原型链的规则不百分百适用于所有情况 显式原型:prototype,是一个对象{} 隐式原型:__proto__,是一个对 ...

  4. 自定义bean对象实现序列化接口

    上一个word count的案例中,我们为了理解mapreduce的流程,写了上面的代码.现在我们要把一个实体类序列化.比如现在有这么一个文件,里面的数据格式是这样的: 第一列是时间戳,第二列是手机号 ...

  5. js屏蔽浏览器默认事件

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. Linux、Ubuntu常用命令

    # 文件解压缩 # zip压缩目录(附带目录权限) zip -q -r html.zip /home/html 压缩目录 tar -zcvf pack.tar.gz pack/ #打包压缩为一个.gz ...

  7. BZOJ4212 神牛的养成计划 (字典树,bitset)

    题面 Description Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望- 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了, ...

  8. 动态规划——leetcode55、跳跃游戏

    1.题目描述:  2.解题方法:动态规划 动态规划解题步骤: 1.确定状态: 最后一步:如果能跳到最后一个下标,我们考虑他的最后一步到n-1(最后一个下标),这一步是从 i 跳过来的,i<n-1 ...

  9. 创建swarm集群并自动编排

    1.基础环境配置 主机名 master node1 node2 IP地址 192.168.***.1 192.168.***.2 192.168.***.3 角色     管理节点 工作节点 工作节点 ...

  10. Tablesaw——Java统计、机器学习库

    资源 java二维数组处理可可视化库 https://github.com/jtablesaw/tablesaw plotly JS库的Java封装 https://github.com/jtable ...