【洛谷 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的点对 思路:牵扯到树上路径的题都是一般都是点分治,我们可以算出所有的路径长 ...
随机推荐
- 记一次艰难的CTP调试
一个atmel,mxt540e的CTP触摸屏. 中断配置为下降沿,输入上拉. 总是只能触发一次中断,中断脚就一直低电平,无法拉高.这只是表面现象 不停找底层I2C驱动,改代码,没用.要靠波形来说话 ...
- Oracle11.2.0.3 RAC配置ODBC成功案例记录
最终使用字符串如下: String url="jdbc:oracle:thin:@(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = scan- ...
- NodeJS微信公众平台开发
微信是手机用户必备的App,微信最开始只是作为社交通讯应用供用户使用,但随着用户量不断的增加,微信的公众号在微信上表现出来了它强大的一面,微信公众平台具有四大优势:1.平台更加稳固:2.用户关系更加平 ...
- jqprint导入jqgrid表格时,内容溢出的原因以及解决方法
jqprint在导入表格的时候,会将原表格的样式全部拉过来,所以说原表格(如jqgrid的表格)的内容在有滚动条的时候,必须得将宽度设置为100%(等百分比的宽度),不能设置成固定宽度,不然表格内容会 ...
- Spring Boot学习(一):入门篇
目录 Spring Boot简介 Spring Boot快速搭建 1 新建项目 2 运行项目 3 设置spring boot可以热部署(修改后端代码后,自动部署,不用手动部署) 3.1:配置pom.x ...
- codeforce580c (dfs)
题目意思:给你一棵树,然后每个叶子节点会有一家餐馆,你讨厌猫,就不会走有连续超过m个节点有猫的路,然后问你最多去几家饭店 思路:直接DFS Example Input 4 11 1 0 01 21 3 ...
- tomcat 启动报错 解决办法 A child container failed during
控制台报错: Caused by: org.apache.catalina.LifecycleException: A child container failed during start at o ...
- JavaScript中常用转义字符
\b 退格 \f 换页 \r 回车 \n 换行 \" 双引号 \' 单引号 \t Tab字符 \\ 反斜杠 \xnn 十六进制代码nn表示的字符 \unnnn 十 ...
- JAVA实现定时器功能
在接口开发时,有一种开发模式叫定时器模式,可以理解为每经过一段预设的时间就会执行一次事件,而在我们的工作中,这个事件所实现的功能一般是将两个系统的数据信息进行同步,这样就实现了两个系统通过接口进行对接 ...
- [洛谷P2824][HEOI2016/TJOI2016]排序
题目大意:一个全排列,两种操作: 1. $0\;l\;r:$把$[l,r]$升序排序2. $1\;l\;r:$把$[l,r]$降序排序 最后询问第$k$位是什么 题解:二分答案,把比这个数大的赋成$1 ...