题目大意:

给一棵有 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. VMware Workstation是可以跟hyper-v 共存的!

    VMware Workstation是可以跟hyper-v 共存的! 神奇的事情 之前一直不知道这个事情,后来发现,原来是可以的,震惊了我的双眼. 我之前一直用的是桌面的Docker Desktop ...

  2. 源码解析springbatch的job是如何运行的?

    202208-源码解析springbatch的job是如何运行的? 注,本文中的demo代码节选于图书<Spring Batch批处理框架>的配套源代码,并做并适配springboot升级 ...

  3. LuoguP3047 [USACO12FEB]附近的牛Nearby Cows(树形DP,容斥)

    \[f[u][step] = \begin{cases} C[u] & step = 0 \\ (\sum{f[v][step - 1]}) - f[u][step - 2] \cdot (d ...

  4. Redis 08 地理位置

    参考源 https://www.bilibili.com/video/BV1S54y1R7SB?spm_id_from=333.999.0.0 版本 本文章基于 Redis 6.2.6 Redis 的 ...

  5. mybatis 15: 缓存

    作用 当对某些数据的查询请求频繁,且数据不经常修改时,使用缓存机制可以提高查询效率 注意 mybatis专注于sql查询,数据映射 缓存问题应该交给专门负责缓存的其他第三方框架 mybatis缓存执行 ...

  6. 如何快速上手AIRIOT?

    AIRIOT物联网低代码平台,快速构建稳定可靠的物联网系统,丰富的功能库及组件库,具备低成本.高效率.易操作,可扩展等特点,节省物联网项目实施时间及人力成本,支持二次开发.   [六步快速上手,玩儿转 ...

  7. .NET 6应用程序适配国产银河麒麟V10系统随记

    最近想在麒麟系统上运行.NET 6程序,经过一番折腾最终完成了,简单记录一下. 目标系统: CPU: aarch64架构(ARM64) 操作系统:银河麒麟V10高级服务器系统 银河麒麟V10系统(以下 ...

  8. 逐层阅读 research paper:Dmitry Berenson 的方法论

    本博客翻译了 这篇文章,包含很实用的 读论文的方法论. 读论文的四个 layers 在读论文之前,要首先搞清楚,自己读论文的目的是什么,或者 希望读到什么程度. 下表列出了常见的读论文目的,以及相应的 ...

  9. [CF1538G] Gift Set (数学简单题)

    题面 相信英文题面也很好理解 有 x \tt x x 个红糖, y \tt y y 个蓝糖.每一个礼包里面要么有 a \tt a a 个红糖+ b \tt b b 个蓝糖,要么是 a \tt a a ...

  10. Queue-jumpers - 平衡树

    题面 Ponyo and Garfield are waiting outside the box-office for their favorite movie. Because queuing i ...