传送门


淀粉质好题啊qaq

我们先考虑随便选择一个点作为邮递中心,通过移动邮递中心找到更优的位置。将路径最大值求出,并将路径最大值对应的那一些路径拿出来考虑。可以知道,如果说这些路径中存在一条经过当前邮递中心的路径,意味着当前点就是最优的(因为不论邮递中心怎么移动,这一条路径的长度不会小于当前值,也就是说答案不会小于当前的最大值),所以只有起点和终点在同一子树内的路径的最长路径才有可能通过移动邮递中心使得答案变得更小。而如果说存在两条路径分布在不同子树内,显然也是无法通过移动使得答案更优的,因为不论邮递中心怎么移动,至少会有一条路径的长度增加。所以只有所有最长路径都在当前邮递中心的一棵子树内的时候,可以通过将邮递中心向子树内移动获得更优的答案。

但是显然每一次都移动一格的复杂度最坏是$O(nm)$的,我们考虑优化。我们可以借助于点分治的思想,每一次移动不是移动到子树的根的位置,而是跳到这一棵子树的重心的位置递归求解,这样的复杂度就是$O(mlogn)$了。

 #include<bits/stdc++.h>
//This code is written by Itst
using namespace std; inline int read(){
int a = ;
bool f = ;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = ;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << ) + (a << ) + (c ^ '');
c = getchar();
}
return f ? -a : a;
} const int MAXN = ;
struct Edge{
int end , upEd , w;
}Ed[MAXN << ];
int head[MAXN] , query[MAXN][] , dis[MAXN] , size[MAXN] , be[MAXN];
int N , M , cntEd , ans , nowSize , minSize , minInd;
bool vis[MAXN]; inline void addEd(int a , int b , int c){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
Ed[cntEd].w = c;
head[a] = cntEd;
} void getSize(int now){
++nowSize;
vis[now] = ;
for(int i = head[now] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end])
getSize(Ed[i].end);
vis[now] = ;
} void getRoot(int now){
int maxN = ;
size[now] = vis[now] = ;
for(int i = head[now] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end]){
getRoot(Ed[i].end);
size[now] += size[Ed[i].end];
maxN = max(maxN , size[Ed[i].end]);
}
maxN = max(maxN , nowSize - size[now]);
if(maxN < minSize){
minSize = maxN;
minInd = now;
}
vis[now] = ;
} void getDis(int now , int fa , int cnt , int len){
be[now] = cnt;
dis[now] = len;
for(int i = head[now] ; i ; i = Ed[i].upEd)
if(Ed[i].end != fa)
getDis(Ed[i].end , now , cnt , len + Ed[i].w);
} void solve(int now){
nowSize = ;
minSize = 0x7fffffff;
getSize(now);
getRoot(now);
int root = minInd , cnt = , maxL = , allBe = ;
vis[root] = ;
dis[root] = be[root] = ;
for(int i = head[root] ; i ; i = Ed[i].upEd)
getDis(Ed[i].end , root , ++cnt , Ed[i].w);
for(int i = ; i <= M ; ++i)
maxL = max(maxL , dis[query[i][]] + dis[query[i][]]);
ans = min(ans , maxL);
for(int i = ; i <= M ; ++i)
if(dis[query[i][]] + dis[query[i][]] == maxL)
if(be[query[i][]] == be[query[i][]] && (!allBe || allBe == be[query[i][]]))
allBe = be[query[i][]];
else
if((!be[query[i][]] || !be[query[i][]]) && (!allBe || allBe == be[query[i][]] + query[i][]))
allBe = be[query[i][]] + be[query[i][]];
else
return;
for(int i = head[root] ; i ; i = Ed[i].upEd)
if(!vis[Ed[i].end] && be[Ed[i].end] == allBe){
solve(Ed[i].end);
return;
}
} int main(){
N = read();
M = read();
ans = ;
for(int i = ; i < N ; ++i){
int a = read() , b = read() , c = read();
addEd(a , b , c);
addEd(b , a , c);
}
for(int i = ; i <= M ; ++i){
query[i][] = read();
query[i][] = read();
}
solve();
printf("%d" , ans);
return ;
}

Luogu4886 快递员 点分治的更多相关文章

  1. [luogu4886] 快递员(点分治,树链剖分,lca)

    dwq推的火题啊. 这题应该不算是点分治,但是用的点分治的思想. 每次找重心,算出每一对询问的答案找到答案最大值,考虑移动答案点,使得最大值减小. 由于这些点一定不能在u的两颗不同的子树里,否则你怎么 ...

  2. Noip前的大抱佛脚----赛前任务

    赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...

  3. 【洛谷 P4886】 快递员 (点分治)

    这题因为一些小细节还是\(debug\)了很久...不过我第一次用脚本对拍,不亏. 先随便找一个点作为根,算出答案,即所有点对到这个点的距离和的最大值,并记录所有距离最大的点对.如果这个点在任意一个距 ...

  4. luogub P4886 快递员(点分治)

    记得是9月月赛题,当时做的时候觉得跟ZJOI2015幻想乡战略游戏那道题很像???,就写了,然后就写挂了... 我们发现假设当前点为根,我们算出\(m\)次询问中最远的\(a\)对点,如果这\(a\) ...

  5. 一篇自己都看不懂的点分治&点分树学习笔记

    淀粉质点分治可真是个好东西 Part A.点分治 众所周知,树上分治算法有$3$种:点分治.边分治.链分治(最后一个似乎就是树链剖分),它们名字的不同是由于分治方式的不同的.点分治,顾名思义,每一次选 ...

  6. 【题解】P4886快递员

    [题解]P4886 快递员 淀粉质好题!!!加深了我对点分治的理解.最近分治学了好多啊. 题目大意 给定你一颗有边权的树,再给你\(m\)和点对,请你在树上选出来一个点,使得所有点对到这个点的距离的最 ...

  7. [bzoj2152][聪聪和可可] (点分治+概率)

    Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...

  8. POJ 2965. The Pilots Brothers' refrigerator 枚举or爆搜or分治

    The Pilots Brothers' refrigerator Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22286 ...

  9. [poj1741][tree] (树/点分治)

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

随机推荐

  1. spring配置log4j

    1.引入log4j-xxx.jar包,buildpath. 2.在项目的根目录下新建resources名的文件夹,注意是source folder,并新建log4j.properties文件 3.在l ...

  2. 原来这样就可以开发出一个百万量级的Android相机

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由QQ空间开发团队发表于云+社区专栏 最近我负责开发了一个跟Android相机有关的需求,新功能允许用户使用手机摄像头,快速拍摄特定尺寸 ...

  3. springcloud 入门 10 (eureka高可用)

    eureka高可用: 说白了,就是加一个实例作为原实例的备份,然后一起对外提供服务.这样可以保证在一台机器宕机的时候,整个系统不会死掉.保证其继续对外服务. eureka的集群化: 服务注册中心Eur ...

  4. 【公众号系列】在SAP里查看条件记录的方法

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[公众号系列]在SAP里查看条件记录的方法   ...

  5. 系统运维|IIS的日志设置

    摘要: 1.服务器告警,磁盘资源不足 2.检查发现是IIS日志没有清理并且设置有误.在E盘占用了200G的空间 3.原则上IIS日志不能放在C盘,避免C盘写满了导致操作系统异常 4.附上IIS日志按天 ...

  6. 【PAT】1083 是否存在相等的差(20 分)

    //这题不是我耍流氓,实在太简单,只能直接贴代码了,凑个数 #include<stdio.h> int aaa[10005]={0}; int main(){ int N;scanf(&q ...

  7. JavaScipt中的Math.ceil() 、Math.floor() 、Math.round()、Math.pow() 三个函数的理解

    以前一直会三个函数的使用产生混淆,现在通过对三个函数的原型定义的理解,其实很容易记住三个函数. 现在做一个总结: 1. Math.ceil()用作向上取整. 2. Math.floor()用作向下取整 ...

  8. jQuery EasyUI combobox多选及赋值

      1.多选属性multiple multiple:true多选 multiple:false单选 <input class="easyui-combobox" id=&qu ...

  9. redis缓存设计

    1:缓存技术和框架的重要性 互联网的一些高并发,高性能的项目和系统中,缓存技术是起着功不可没的作用.缓存不仅仅是key-value的简单存取,它在具体的业务场景中,还是很复杂的,需要很强的架构设计能力 ...

  10. 1346:【例4-7】亲戚(relation)

    并查集的模板题: #include<iostream> #include<cstdio> using namespace std; ; int fa[maxn]; int fi ...