传送门啦

要求的就是,把树上的一条边的权值设为0之后,所有路径中的最大值的最小值。

首先二分最大值,假设某次二分的最大值为x,我们首先找出所有大于x的路径(也就是我们需要通过改权缩短的路径),并把路径上的所有边都标记一下。

在标记完成后,枚举所有边,如果存在一条边位于所有长度大于于x的路径上,并且删除之后能使所有路径都满足 $ length<=x $ ,则返回 $ true $ ,否则 $ false $ 。

还有一个问题就是,对于某个路径,如何快速标记出他经过的所有边呢?我们可以使用差分,用树上前缀和来表示某个点被标记次数。比如某条边 $ E(u,v) $ ,先把 $ sum[u]+=1,sum[v]+=1 $ ,然后 $ sum[lca(u,v)]-=2 $

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define re register
using namespace std;
const int maxn = 300005; inline int read(){
char ch = getchar();
int f = 1 , x = 0;
while(ch > '9' || ch < '0'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
return x * f;
} int n,m,a,b,t,u[maxn],v[maxn];
int head[maxn],tot;
int f[maxn][21],ans; struct Edge{
int from,to,val,next;
}edge[maxn << 1]; inline void add(int u , int v , int w){
edge[++tot].from = u;
edge[tot].to = v;
edge[tot].val = w;
edge[tot].next = head[u];
head[u] = tot;
} int dep[maxn],dis[maxn],value[maxn],len[maxn];
int id[maxn],cnt; inline void dfs(int x , int fa) {
id[++cnt] = x;
dep[x] = dep[fa] + 1;
f[x][0] = fa;
for(re int i = 1 ; (1 << i ) <= dep[x] ; ++i)
f[x][i] = f[f[x][i - 1]][i - 1];
for(re int i = head[x] ; i ; i = edge[i].next) {
int v = edge[i].to;
if(v == fa) continue;
dis[v] = dis[x] + edge[i].val;
value[v] = edge[i].val;
dfs(v , x);
}
} inline int lca(int u , int v){
if(dep[u] < dep[v]) swap(u , v);
for(re int i = 18 ; i >= 0 ; --i)
if((1 << i) <= (dep[u] - dep[v]))
u = f[u][i];
if(u == v) return u;
for(re int i = 18 ; i >= 0 ; --i){
if((1 << i) <= dep[u] && f[u][i] != f[v][i]) {
u = f[u][i] ;
v = f[v][i] ;
}
}
return f[u][0];
} int sum[maxn]; inline bool check(int k){
for(re int i = 1 ; i <= n ; ++i)
sum[i] = 0;
int maxx = 0 , cnt = 0 ;
for(re int i = 1 ; i <= m ; ++i) {
if(len[i] > k) {
maxx = max(maxx , len[i]) ;
cnt++;
sum[u[i]]++; sum[v[i]]++;
sum[lca(u[i] , v[i])] -= 2;
}
}
for(re int i = n ; i >= 0 ; i--)
sum[f[id[i]][0]] += sum[id[i]] ;
for(re int i = 1 ; i <= n ; ++i)
if(sum[i] >= cnt && maxx - value[i] <= k)
return true;
return false;
} int main(){
n = read() ; m = read();
for(re int i = 1 ; i <= n - 1 ; ++i){
a = read(); b = read(); t = read();
add(a , b , t);
add(b , a , t);
}
dfs(1 , 0);
int l = 0 , r = 0 ;
for(re int i = 1 ; i <= m ; ++i){
u[i] = read(); v[i] = read();
len[i] = dis[u[i]] + dis[v[i]] - 2 * dis[lca(u[i] , v[i])] ;
r = max(r , len[i]);
}
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;
}

洛谷P2680运输计划的更多相关文章

  1. 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)

    P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...

  2. 洛谷 P2680 运输计划 解题报告

    P2680 运输计划 题目背景 公元2044年,人类进入了宇宙纪元. 题目描述 公元2044年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道,每条航道建立在两个星 ...

  3. [NOIP2015] 提高组 洛谷P2680 运输计划

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...

  4. 洛谷P2680 运输计划 [LCA,树上差分,二分答案]

    题目传送门 运输计划 Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n?1 条双向航道,每条航道建立在两个星球之间, 这 n?1 条航道连通了 L 国的所 ...

  5. 洛谷 P2680 运输计划(NOIP2015提高组)(BZOJ4326)

    题目背景 公元 \(2044\) 年,人类进入了宇宙纪元. 题目描述 公元\(2044\) 年,人类进入了宇宙纪元. L 国有 \(n\) 个星球,还有 \(n-1\) 条双向航道,每条航道建立在两个 ...

  6. 洛谷 P2680 运输计划

    题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...

  7. 洛谷——P2680 运输计划

    https://www.luogu.org/problem/show?pid=2680 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每 ...

  8. 洛谷P2680 运输计划——树上差分

    题目:https://www.luogu.org/problemnew/show/P2680 久违地1A了好高兴啊! 首先,要最大值最小,很容易想到二分: 判断当前的 mid 是否可行,需要看看有没有 ...

  9. 洛谷P2680 运输计划

    大概就是二分+树上差分... 题意:给你树上m条路径,你要把一条边权变为0,使最长的路径最短. 最大的最小,看出二分(事实上我并没有看出来...) 然后二分k,对于所有大于k的边,树上差分求出最长公共 ...

随机推荐

  1. APK反编译之二:工具介绍

    前面一节我们说过,修改APK最终是通过修改smali来实现的,所以我们接下来介绍的工具就是如何把APK中的smali文件获取出来,当然同时也需要得到AndroidManifest.xml等文件.直接修 ...

  2. 【cf859E】Desk Disorder

    Portal --> cf859E Solution ​​ 我们可以将每一个人看成一条边,将位置看成点,然后一个人在新的方案中可以选择的位置就是这条边连接的两个点,然后我们就得到了一个图 ​ 注 ...

  3. where EXISTS (子查询)多对多中通过中间表查对方列表

    用户表A,小组表B,小组和用户是多对多关系,中间有个中间表M 已知 小组 id 即teamId ,想知道这个小组中的用户列表信息,可以如下写sql: select * from A a where E ...

  4. struts2为什么action要继承actionSupport类

    我们为了方便实现Action,大多数情况下都会继承com.opensymphony.xwork2.ActionSupport类, 并重载(Override)此类里的String execute()方法 ...

  5. js基础之DOM中document对象的常用属性方法

    -----引入 每个载入浏览器的 HTML 文档都会成为 Document 对象. Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问. 属性 1  document.an ...

  6. Java基础-面向接口(interface)编程

    Java基础-面向接口(interface)编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的“类 ...

  7. [转载]IIS6.0开启WOFF/SVG文件支持

    http://www.bao21.com/120.html http://stackoverflow.com/questions/18369036/bootstrap-3-glyphicons-not ...

  8. [整理]C语言中的static静态对象

    1.说明外部对象(静态外部变量和静态函数)    (1)static 用于说明外部变量或函数,使该对象的作用域限定为被编译原文件的剩余部分,即从对象说明开始到所在源文件的结束部分:    (2)被st ...

  9. zookeeper日常报错总结

    1:创建子节点的时候 没有根节点 org.apache.zookeeper.KeeperException$NoNodeException: KeeperErrorCode = NoNode for ...

  10. c++刷题(21/100)树的打印、矩阵覆盖和括号生成

    题目一:把二叉树打印成多行 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 思路:一开始以为2维的vector可以直接访问,但是试了是不行,会报错,vector在有值之前不能直接访问 ...