这题因为一些小细节还是\(debug\)了很久。。。不过我第一次用脚本对拍,不亏。

先随便找一个点作为根,算出答案,即所有点对到这个点的距离和的最大值,并记录所有距离最大的点对。如果这个点在任意一个距离最大的点对之间的路径上,那么答案显然不能再优了,因为这个点对的答案是不能减小了的。如果有两个距离最大的点对不在根的同一子树中,答案也是显然不能再优了的,因为一个点对答案减小的同时,另一个会增大。只有当所有距离最大的点对在根的同一子树中,这时更优答案可能在这个子树里,向这个子树递归处理就行了。为什么说可能?因为往这个子树走的同时可能会存在在另一个子树中原本不是距离最大的点对变为距离最大的点对,所以我们要一直对答案取最小值。直接走最多会走\(n\)次,而如果我们每次都走子树的重心,最多走\(logN\)次,所以总时间复杂度\(O(m\log n)\)。

现在讲讲具体怎么实现,主要就难在怎么判断根在不在两个点之间的路径上。求\(LCA\)是最简单粗暴的方法,但时间复杂度要多一个\(log\),其实类似于点分治里的统计,只需要看这个点对的两个点在不在同一子树里就行了,若在,则路径不经过根,反之亦然。

然后,看\(Code\)吧。

#include <iostream>
#include <cstdio>
#define INF 2147483647
using namespace std;
inline int read(){int s = 0, w = 1;char ch = getchar();while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }return s * w;
}
const int MAXN = 100010;
struct Edge{int next, to, dis;
}e[MAXN << 1];
int head[MAXN], num, x[MAXN], y[MAXN], vis[MAXN], maxson[MAXN], p[MAXN], q[MAXN], belong[MAXN], deep[MAXN], size[MAXN];
int n, m, root, Max, ans = 2147483647;
inline void Add(int from, int to, int dis){e[++num].to = to;e[num].dis = dis;e[num].next = head[from];head[from] = num;
}
void getRoot(int u,int fa,int ALL){   //找重心size[u] = 1; maxson[u] = 0;for(int i = head[u]; i; i = e[i].next)if(e[i].to != fa && !vis[e[i].to]){getRoot(e[i].to, u, ALL);size[u] += size[e[i].to];maxson[u] = max(maxson[u], size[e[i].to]);}maxson[u] = max(maxson[u], ALL - size[u]);if(maxson[u] < Max) root = u, Max = maxson[u];
}
void dfs(int u, int fa, int dep, int rt){ //算出每个点的深度,并标记属于根的哪棵子树belong[u] = rt;deep[u] = dep;for(int i = head[u]; i; i = e[i].next)if(e[i].to != fa)dfs(e[i].to, u, dep + e[i].dis, rt);
}
void Solve(int u){if(vis[u]){printf("%d\n", ans);exit(0);}      vis[u] = 1;for(int i = head[u]; i; i = e[i].next)dfs(e[i].to, u, e[i].dis, e[i].to);deep[u] = 0;Max = 0; p[0] = 0;int last = 0;for(int i = 1; i <= m; ++i)    //找出所有距离最大的点对并求出答案if(deep[x[i]] + deep[y[i]] > Max) Max = deep[x[i]] + deep[y[i]], p[p[0] = 1] = i;else if(deep[x[i]] + deep[y[i]] == Max)p[++p[0]] = i;ans = min(ans, Max);   //更新答案for(int i = 1; i <= p[0]; ++i){if(belong[x[p[i]]] != belong[y[p[i]]]){  //如果有一个点对之间的路径经过根,当前答案一定是最优的printf("%d\n", ans);exit(0);}else if(!last) last = belong[x[p[i]]];else if(last != belong[x[p[i]]]){  //如果两个点对不在同一子树里,当前答案也一定最优printf("%d\n", ans);exit(0);}}Max = 9996666;getRoot(last, u, size[last]);  //找子树的重心Solve(root);   //递归处理
}
int a, b, c;
int main(){n = read(); m = read();for(int i = 2; i <= n; ++i){a = read(); b = read(); c = read(); Add(a, b, c); Add(b, a, c);}for(int i = 1; i <= m; ++i){x[i] = read(); y[i] = read();}Max = 9996666; getRoot(1, 0, n);Solve(root);return 0;
}

转载于:https://www.cnblogs.com/Qihoo360/p/9675522.html

【洛谷 P4886】 快递员 (点分治)相关推荐

  1. 洛谷T44252 线索_分治线段树_思维题

    分治线段树,其实就是将标记永久化,到最后再统一下传所有标记. 至于先后顺序,可以给每个节点开一个时间戳. 一般地,分治线段树用于离线,只查询一次答案的题目. 本题中,标记要被下传 222 次. Cod ...

  2. 洛谷 4178 Tree——点分治

    题目:https://www.luogu.org/problemnew/show/P4178 点分治.如果把每次的 dis 和 K-dis 都离散化,用树状数组找,是O(n*logn*logn),会T ...

  3. 洛谷 P1498 南蛮图腾 分治递归过程详解

    题目描述 自从到了南蛮之地,孔明不仅把孟获收拾的服服帖帖,而且还发现了不少少数民族的智慧,他发现少数民族的图腾往往有着一种分形的效果,在得到了酋长的传授后,孔明掌握了不少绘图技术,但唯独不会画他们的图 ...

  4. 洛谷 P2400 秘密文件【分治】

    ... 题目: 题意: 分析: 代码: 题目: 传送门 题意: 给出一个较长的字符串,要求我们按照规则进行化简,使得其长度最短 分析: 直接使用分治的思想,对于区间l−rl-rl−r,我们枚举一个分界 ...

  5. 洛谷 4115 Qtree4——链分治

    题目:https://www.luogu.org/problemnew/show/P4115 论文:https://wenku.baidu.com/view/1bc2e4ea172ded630b1cb ...

  6. [WC2005]双面棋盘,洛谷P4121,线段树分治+可撤销并查集

    正题 这题主要是来练手的,因为没写过可撤销的并查集,大概就是把每一个格子看成一个点,然后格子直接的边有很多的出现区间,把这些出现区间和对应的颜色打到线段树上,然后用可撤销的并查集来维护就可以了. #i ...

  7. 【洛谷习题】南蛮图腾

    题目链接:https://www.luogu.org/problemnew/show/P1498 不好实现... 这道题在洛谷的分类是分治,我用的方法就是分治,不过却刷新的我对分治的认识.以前见过的分 ...

  8. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

  9. 分治——Secret Cow Code S(洛谷 P3612)

    题目选自洛谷P3612 梳理题意 给定一个字符串,每次将其最后一个字符移到最前方,形成的新串接到原串后作为下一次操作的字符串 现询问第 N 个位置的字符 简要分析 看一眼数据范围,N<10^18 ...

最新文章

  1. oracle delete原理,如何恢复并理解oracle删除数据的原理
  2. android e图标一会有一会没有反应,android解决菜单Menu添加Icon无效问题,让菜单同时显示图标和文字...
  3. Spring IOC容器-Bean管理——基于XML方式
  4. html的canvas显示数字,HTML5效果:Canvas 实现圆形进度条并显示数字百分比
  5. Tab Space:超棒的Safari浏览器标签快速保存工具
  6. 粗略写了使用GD2制作文字图像demo
  7. ubuntu20.04 搭建tftp服务器
  8. 苏州旅游网站的设计与实现 毕业论文+Html静态源码
  9. js中 attachEvent事件
  10. html计算100以内偶数和,学习脚本1:计算100以内奇数和和偶数和 (笔记)
  11. SQL存储过程前面后面的几句代码是什么意思?
  12. 你玩的英雄在比赛中发挥如何呢?
  13. 「 Gazebo仿真 」地图创建、多模型显示、基本指令
  14. 美丽的诗句 撩妹首选哦!
  15. 红米K30S至尊纪念版和小米10至尊纪念版的区别
  16. ios-跳转到苹果自带地图进行导航
  17. 为梦想加油:7个值得深思的名人财富故事
  18. JUC并发编程(1.Java线程)
  19. java猜数字游戏课程设计报告_Java程序设计课程设计-猜数字游戏设计.doc
  20. 服务器磁盘管理(分区和挂载)

热门文章

  1. 微软发布 PowerToys 0.12.0,带来批量处理工具和暗黑模式
  2. 发现Tensorflow
  3. mysql是表级锁还是行级锁_带你了解MySQL数据库中的全局锁、表级锁、行级锁
  4. 计算机基础第1次作业,计算机应用基础 第一次作业
  5. mysql的大字段clob,Oracle数据库导出大字段(CLOB)数据
  6. antd中tooltip换行_ant design 中实现表格头部可删除和添加
  7. 用C语言写ucos中断服务程序,在ARM处理器上移植uCOS II的中断处理
  8. polkit启动失败_linux某服务启动失败,提示Authorization not available. Check if polkit...问题解决...
  9. php 2个经纬度之间的距离,php计算两个经纬度之间的距离
  10. ubuntu 编译安装nginx php mysql_ubuntu下安装nginx php mysql