传送门


淀粉质好题啊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. 学习css(TODO)

    1. css 是一个什么样的角色? 答:css 负责控制网页的样式. 扩展:div + css 是经典的网页布局.实现网页内容与表现相分离. 2. css 的使用方式? 答:1. 内联式:直接在 HT ...

  2. MIPS 安全相关paper阅读笔记

    前言 论文来自 ​ https://cyber-itl.org/2018/12/07/a-look-at-home-routers-and-linux-mips.html Linux_MIPS_mis ...

  3. Android 云之声离线语音合成

    离线语音解析 public class SpeechUtilOffline implements TTSPlayerListener { public static final String appK ...

  4. Django 拾遗

    1.python_2_unicode_compatible装饰器 from django.db import models from django.utils.encoding import pyth ...

  5. python与MongoDB的基本交互:pymongo

    本文内容: pymongo的使用: 安装模块 导入模块 连接mongod 获取\切换数据库 选择集合 CRUD操作 首发时间:2018-03-18 20:11 pymongo的使用: 安装模块: pi ...

  6. 04-openldap客户端安装

    阅读视图 基础环境准备 关闭sssd及安装nslcd客户端 配置nslcd客户端 启动nslcd进程 客户端验证 ssh登录自动创建家目录 1. 基础环境准备 本文承接openldap服务端安装配置, ...

  7. 找Maven --> pom.xml --> groupId和artifactId的网站

    http://mvnrepository.com/ 在此记录

  8. js中var的有或无--重复声明和以后的声明

    js中var的有或无--重复声明和以后的声明 使用var语句多次声明一个变量不仅是合法的,而且也不会造成任何错误. 如果重复使用的一个声明有一个初始值,那么它担当的不过是一个赋值语句的角色. 如果重复 ...

  9. ARM有几条memory barrier 的指令?分别有什么区别?

    从ARMv7指令集开始,ARM提供3条内存屏障指令. (1)数据存储屏障( Data Memory Barrier,DMB) 数据存储器隔离.DMB指令保证:仅当所有在它前面的存储器访问操作都执行完毕 ...

  10. .net 调用R语言的函数(计算统计值pvalue 对应excel :ttest)

    Pvalue 计算 项目设计pvalue计算,但是由于.net 没有类似的公式或者函数,最终决定使用.net 调用R语言 采用.net 调用r语言的公用函数 需要安装 r语言环境 https://mi ...