luogub P4886 快递员(点分治)
记得是9月月赛题,当时做的时候觉得跟ZJOI2015幻想乡战略游戏那道题很像???,就写了,然后就写挂了。。。
我们发现假设当前点为根,我们算出\(m\)次询问中最远的\(a\)对点,如果这\(a\)对点,全部都两个点在根的不同子树中。当前点就是最优的就是答案。当全部\(a\)对点都在一个子树中,我们把答案改为那个子树对应的儿子,答案会变优。当有几对点在一个子树,另外几对点在另外的子树中,当前答案还是最优的。
所以本题的一个想法就是,一个一个的改变根使答案变优。
但是上述想法要求我们每一次移动一个点都要遍历整棵树。是在太慢了。
我们考虑用点分治的方法优化算法。当全部\(a\)对点都在一个子树中时,一个更优的答案在那个子树中,我们找到这个子树的重心当作根。这样最多遍历\(logn\)次。把复杂度变为了\(O(mlogn)\)。至此本题得到完美解决。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=101000;
int cnt,head[N];
int g[N],size[N],all,root,dis[N],ans1[N],ans2[N],dep[N],fa[N][25],vis[N];
int n,m,a[N],b[N],ans;
struct edge{
int to,nxt,w;
}e[N*2];
void add_edge(int u,int v,int w){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
e[cnt].w=w;
head[u]=cnt;
}
int read(){
int sum=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
void getroot(int u,int f){
g[u]=0;size[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v]||f==v)continue;
getroot(v,u);
size[u]+=size[v];
g[u]=max(g[u],size[v]);
}
g[u]=max(g[u],all-g[u]);
if(g[u]<g[root])root=u;
}
void getdis(int u,int f,int w){
dep[u]=dep[f]+1;
fa[u][0]=f;
dis[u]=w;
for(int i=1;i<=20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f)continue;
getdis(v,u,w+e[i].w);
}
}
int getlca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int up(int u,int x){
for(int i=20;i>=0;i--)
if((x>>i)&1)u=fa[u][i],x-=(1<<i);
return u;
}
int calc(int u){
getdis(u,0,0);
int tmp=0;
for(int i=1;i<=m;i++){
int x=dis[a[i]]+dis[b[i]];
if(x>tmp){
cnt=0;
ans1[++cnt]=a[i];ans2[cnt]=b[i];
tmp=x;
}
}
ans=min(ans,tmp);
tmp=0;
for(int i=1;i<=cnt;i++){
int x=up(ans1[i],dep[ans1[i]]-dep[u]-1);
int y=up(ans2[i],dep[ans2[i]]-dep[u]-1);
if(x==y){
if(tmp==0)tmp=x;
else return -1;
}
}
if(tmp==-1)return -1;
return tmp;
}
void work(int u){
int x=calc(u);
if(x==-1)return;vis[u]=1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(vis[v])continue;
if(v==x){
root=0;all=size[v];
getroot(v,0);
work(root);
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<n;i++){
int u=read(),v=read(),w=read();
add_edge(u,v,w);add_edge(v,u,w);
}
for(int i=1;i<=m;i++)a[i]=read(),b[i]=read();
ans=1e9;
g[0]=n+10,all=n;
getroot(1,0);work(root);
printf("%d",ans);
return 0;
}
luogub P4886 快递员(点分治)的更多相关文章
- 【题解】P4886快递员
[题解]P4886 快递员 淀粉质好题!!!加深了我对点分治的理解.最近分治学了好多啊. 题目大意 给定你一颗有边权的树,再给你\(m\)和点对,请你在树上选出来一个点,使得所有点对到这个点的距离的最 ...
- [P4886] 快递员
考虑在树上选个点rt作为根,并且快递中心就选这儿.计算出所有配送的代价(2*两段之和),设他们的最大值为Max.若此时存在下列情况时,可以判定Max已经为最优解. 1)存在代价为Max的配送(u,v) ...
- Luogu4886 快递员 点分治
传送门 淀粉质好题啊qaq 我们先考虑随便选择一个点作为邮递中心,通过移动邮递中心找到更优的位置.将路径最大值求出,并将路径最大值对应的那一些路径拿出来考虑.可以知道,如果说这些路径中存在一条经过当前 ...
- [洛谷P4886]快递员
题目大意:一个$n$个点的树,树上有$m$个点对$(a,b)$,找到一个点$x$,使得$max(dis(x,a_i)+dis(x,b_i))$最小 如果做过幻想乡的战略游戏这道题,应该这道题的思路一眼 ...
- [luogu4886] 快递员(点分治,树链剖分,lca)
dwq推的火题啊. 这题应该不算是点分治,但是用的点分治的思想. 每次找重心,算出每一对询问的答案找到答案最大值,考虑移动答案点,使得最大值减小. 由于这些点一定不能在u的两颗不同的子树里,否则你怎么 ...
- 【洛谷 P4886】 快递员 (点分治)
这题因为一些小细节还是\(debug\)了很久...不过我第一次用脚本对拍,不亏. 先随便找一个点作为根,算出答案,即所有点对到这个点的距离和的最大值,并记录所有距离最大的点对.如果这个点在任意一个距 ...
- 一篇自己都看不懂的点分治&点分树学习笔记
淀粉质点分治可真是个好东西 Part A.点分治 众所周知,树上分治算法有$3$种:点分治.边分治.链分治(最后一个似乎就是树链剖分),它们名字的不同是由于分治方式的不同的.点分治,顾名思义,每一次选 ...
- [bzoj2152][聪聪和可可] (点分治+概率)
Description 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好 ...
- POJ 2965. The Pilots Brothers' refrigerator 枚举or爆搜or分治
The Pilots Brothers' refrigerator Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 22286 ...
随机推荐
- ZBrush中如何使用套索工具绘制遮罩
ZBrush®中创建遮罩的方法有很多,可以手动创建矩形遮罩.圆形遮罩和图案遮罩,然而这些遮罩都是固定的形状.使用Zbrush中的套索遮罩能够实现不规则的图形遮罩,游刃有余的发挥创作. 使用套索工具绘制 ...
- CentOS 6.5下部署日志服务器 Rsyslog+LogAnalyzer+MySQL
简介 LogAnalyzer 是一款syslog日志和其他网络事件数据的Web前端.它提供了对日志的简单浏览.搜索.基本分析和一些图表报告的功能.数据可以从数据库或一般的syslog文本文件中获取,所 ...
- Qwiklab'实验-Hadoop, IoT, IAM, Key Management'
title: AWS之Qwiklab subtitle: 1. Qwiklab'实验-Hadoop, IoT, IAM, Key Management Service' date: 2018-09-1 ...
- laravel 知识点总结
1.eloquent 关系理解: https://lvwenhan.com/laravel/423.html
- [读书笔记] R语言实战 (三) 图形初阶
创建图形,保存图形,修改特征:标题,坐标轴,标签,颜色,线条,符号,文本标注. 1. 一个简单的例子 #输出到图形到pdf文件 pdf("mygrapg.pdf") attach( ...
- unity 支持圆形、切倒角和虚化UGUI Shader
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt ...
- java源码之Comparable和Comparator
1,Comparable 简介 Comparable 是排序接口. 若一个类实现了Comparable接口,就意味着“该类支持排序”. 即然实现Comparable接口的类支持排序,假设现在存在“实 ...
- 确保 Xcode 每次 Build 时都自己主动更新资源
參考:p=22" target="_blank">http://quick.cocoachina.com/?p=22 刚建立的quickproject.每次修改lu ...
- Android 开发之集成百度地图的定位与地图展示
app 应用中,大多数应用都具有定位功能,百度定位就成了开发人员的集成定位功能的首选,近期也在做定位功能,可是发现百度真是个大坑啊, sdk 命名更新了,相关代码却不更新,害得我花费了非常长时间来研究 ...
- OC 自己定义 setDateFormat 显示格式
-(NSString *)getStringFromDate:(NSDate *)aDate { NSDateFormatter *dateFormater=[[NSDateFormatter all ...