题目背景

公元 2044 年,人类进入了宇宙纪元。

题目描述

L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条

航道连通了 L 国的所有星球。

小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物

流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。

为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。

如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?

$Solution:$

其实挺简单的……跟保卫王国什么的没法比……

题意就是给你几条树上路径,有一次删除边权的机会,最小化它们的最大长度。“最大值最小”显然二分啊。

考虑怎么check,首先如果二分出的$ans \ge $最长路径长度那么一定是合法的,不过没什么用,因为完全可以把二分右端点设为最长路径长度。

我们可以无视长度$\leq ans$的路径,那么接下来要做的,就是利用删除边权操作在答案中消去最长路径长度$-ans$这么大(设为w)的长度。在剩下的路径中,如果存在一条这些路径的公共边满足边权$\ge w$,就可以判定为合法的。

求路径的公共边可以转化为求树边覆盖次数,树上差分板子,注意对于边的差分是x++,y++,lca-=2。

然后路径长什么的直接lca求解即可。

由于它是一道有尊严的D2T3,所以肯定会防AK。卡一下二分左右边界可以苟过去= =。

#include<cstdio>
#include<iostream>
#include<cstring>
#define pa pair<int,int>
#define re register
using namespace std; const int L=1<<20|1;
char buffer[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=3e5+5;
int n,m,to[N<<1],head[N],nxt[N<<1],tot,w[N<<1];
int size[N],son[N],top[N],fa[N],dep[N],dis[N];
pa p[N];
int D[N],_lca[N],dif[N],maxw;
inline void add(int x,int y,int z)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
w[tot]=z;
}
void dfs1(int x,int f)
{
fa[x]=f;dep[x]=dep[f]+1;size[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==f)continue;
dis[y]=dis[x]+w[i];
dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]])son[x]=y;
}
}
void dfs2(int x,int Top)
{
top[x]=Top;
if(son[x])dfs2(son[x],Top);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(top[y])continue;
dfs2(y,y);
}
}
inline int lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return x;
}
void dfs(int x)
{
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x])continue;
dfs(y);
dif[x]+=dif[y];
}
}
bool judge(int x,int cnt,int len)
{
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa[x])continue;
if(dif[y]==cnt&&w[i]>=len)return 1;
if(judge(y,cnt,len))return 1;
}
return 0;
} inline bool check(int val)
{
if(maxw<=val)return 1;
for(re int i=1;i<=n;i++)dif[i]=0;
int cnt=0;
for(re int i=1;i<=m;i++)
{
if(D[i]<=val)continue;
cnt++;
dif[p[i].first]++;dif[p[i].second]++;
dif[_lca[i]]-=2;
}
dfs(1);
return judge(1,cnt,maxw-val);
} int main()
{
n=read();m=read();
int maxe=0;
for(re int i=1;i<n;i++)
{
int x=read(),y=read(),z=read();
add(x,y,z);add(y,x,z);
maxe=max(maxe,z);
}
dfs1(1,0);dfs2(1,1); for(re int i=1;i<=m;i++)
{
int x=read(),y=read(),LCA=lca(x,y);
p[i]=make_pair(x,y);
D[i]=dis[x]+dis[y]-2*dis[LCA];
maxw=max(maxw,D[i]);
_lca[i]=LCA;
}
int l=maxw-maxe,r=maxw,ans=r;
while(l<=r)
{
int mid=l+r>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}

最新文章

  1. LeetCode 258. Add Digits
  2. Fiddler (二) Script 用法
  3. 按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。 创建第
  4. sftp配置
  5. 第二百一十二天 how can I 坚持
  6. 全代码实现ios-3
  7. CMMI 配置管理
  8. 微信朋友圈分享页面(JS-SDK 1.0)
  9. vs2012如何创建报表
  10. JSP实现数据库(MySQL)查询——Java Web练习(二)
  11. BMP 转 YUV (BMP2YUV)
  12. 【问题】VS问题集合,不用也要收藏防止以后使用找不到
  13. 英语笔记3(git)
  14. 【bzoj 3786】星系探索
  15. 什么是Unicode
  16. HttpWatch Professional Edition 7.2.13下载含( license.lic )
  17. ESB架构之企业实施案例
  18. JS 计算时间差,(引入外部字体文件)
  19. 20155230 2016-2017-2 《Java程序设计》第三周学习总结
  20. 【云安全与同态加密_调研分析(2)】国外云安全标准建议组织——By Me

热门文章

  1. 3 深入解析controlfile
  2. Zotero引用文献格式(软件学报)
  3. C#里sqlDataAdapter.fill(DataSet,String)的用法
  4. Git利用命令行提交代码步骤
  5. Oracle DBA_EXTENTS视图 与 DBA_SEGMENTS视图
  6. VUE:v-for获取列表前n个数据、中间范围数据、末尾n条数据的方法
  7. 微信公众号获取微信token
  8. ES6——面向对象应用
  9. srs-librtmp pusher(push h264 raw)
  10. linux NFS 的安装准备