【洛谷 P4886】 快递员 (点分治)
这题因为一些小细节还是\(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;
}
【洛谷 P4886】 快递员 (点分治)的更多相关文章
- [洛谷P4886]快递员
题目大意:一个$n$个点的树,树上有$m$个点对$(a,b)$,找到一个点$x$,使得$max(dis(x,a_i)+dis(x,b_i))$最小 如果做过幻想乡的战略游戏这道题,应该这道题的思路一眼 ...
- 洛谷P3810 陌上花开 CDQ分治(三维偏序)
好,这是一道三维偏序的模板题 当然没那么简单..... 首先谴责洛谷一下:可怜的陌上花开的题面被无情的消灭了: 这么好听的名字#(滑稽) 那么我们看了题面后就发现:这就是一个三维偏序.只不过ans不加 ...
- [洛谷P3806] [模板] 点分治1
洛谷 P3806 传送门 这个点分治都不用减掉子树里的了,直接搞就行了. 注意第63行 if(qu[k]>=buf[j]) 不能不写,也不能写成>. 因为这个WA了半天...... 如果m ...
- 洛谷P4390 Mokia CDQ分治
喜闻乐见的CDQ分治被我搞的又WA又T..... 大致思路是这样的:把询问用二维前缀和的思想拆成4个子询问.然后施CDQ大法即可. 我却灵光一闪:树状数组是可以求区间和的,那么我们只拆成两个子询问不就 ...
- 洛谷P4178 Tree (点分治)
题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...
- 洛谷 4178 Tree——点分治
题目:https://www.luogu.org/problemnew/show/P4178 点分治.如果把每次的 dis 和 K-dis 都离散化,用树状数组找,是O(n*logn*logn),会T ...
- 洛谷T44252 线索_分治线段树_思维题
分治线段树,其实就是将标记永久化,到最后再统一下传所有标记. 至于先后顺序,可以给每个节点开一个时间戳. 一般地,分治线段树用于离线,只查询一次答案的题目. 本题中,标记要被下传 222 次. Cod ...
- 洛谷 P4149 [IOI2011]Race-树分治(点分治,不容斥版)+读入挂-树上求一条路径,权值和等于 K,且边的数量最小
P4149 [IOI2011]Race 题目描述 给一棵树,每条边有权.求一条简单路径,权值和等于 KK,且边的数量最小. 输入格式 第一行包含两个整数 n, Kn,K. 接下来 n - 1n−1 行 ...
- 洛谷 P3806 (点分治)
题目:https://www.luogu.org/problem/P3806 题意:一棵树,下面有q个询问,问是否有距离为k的点对 思路:牵扯到树上路径的题都是一般都是点分治,我们可以算出所有的路径长 ...
随机推荐
- leetcode笔记--2 reverse string
my answer: 出错点:new_list[s] = list_s[u-1-s] 这样会出错, 重点:(1) map(str, s) 函数的使用,例:ls = [1,2,3]rs = map(st ...
- 如何搭建SBT编译Scala开发的Android工程
作者:戚明峰 最近接触了shadowsocks的Android客户端项目源码(https://github.com/shadowsocks/shadowsocks-android),刚好这个项目是使用 ...
- 获取已安装app的bundle id
备注:以下是私有api 苹果审核会被拒绝. 导入头文件 #import <objc/runtime.h> /// 获取其他APP信息(iOS11无效) + (NSArray *)getOt ...
- windows 10 下的linux子系统用法 -- tmux分屏工具用法
1 激活linux子系统的方法见百度: 2 打开powershell,输入bash启动子系统终端:输入exit退出: 3 输入tmux attach连接会话:ctrl-b+d 返回终端:ctrl-b+ ...
- c++ combination by next_permutation
#include <iostream> #include <algorithm> #include <vector> int main() { int n, r; ...
- 『JavaScript』new关键字
原文 new关键字做了什么 在JavaScript中,使用new关键字后,意味着做了如下四件事情: 创建一个新的对象,这个对象的类型是object: 设置这个新的对象的内部.可访问性和[[protot ...
- bugku 字符正则
字符?正则? <?php highlight_file('2.php'); $key='KEY{********************************}'; $IM= preg_mat ...
- 接口测试工具postman(三)添加断言
每个用例执行完成后,可以通过添加断言来判断返回结果是否正确,即表示用例执行是否成功. 官方说明文档:https://learning.getpostman.com/docs/postman/scrip ...
- QC的使用学习(一)
今天学习的时间很少,就利用睡前的一点时间来学习一下刚安装好的QC. 1.后台站点管理.主要是对八大选项的了解: site project:顾名思义,就站点项目管理,管理域和项目. site user: ...
- spring boot 过滤器实现接收 压缩数据 并解压
1.新加类GzipRequestWrapper 继承HttpServletRequestWrapper类 public class GzipRequestWrapper extends HttpSer ...