题目链接


题解

题意

一棵树上有\(m\)条路径,可以将其中一条边的权值改为0,问最长的路径最短是多少

分析

  • 最短的路径最长自然想到二分最长路径,设其为\(dis\)
  • 关键在于如何check
  • check的关键又是将哪条边改为0
  • 贪心,如果所有超过\(dis\)的路径能在一条边上重合,则将那条边改为0,之后再判断改为0后是否最大的路径小于\(dis\);若无法将所有超过\(dis\)的边重合在一条边上,直接return false;

做法

  • 算两个点之间的路径长用dfs + LCA来实现
  • 判断路径之间的重合用树上差分来实现
  • 这里用的是倍增

注意事项

无向边要把数组开两倍!!!

代码

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring> using namespace std; const int MAXN = 500500;
int n, m;
int logn;
int u[MAXN], v[MAXN], lca[MAXN];
int vis[MAXN], dep[MAXN], fa[MAXN][25];
int dfn[MAXN], Index, Edge_cnt;
int Max_dis = -1, treeC[MAXN], predis[MAXN], dissum[MAXN], distence[MAXN]; int ecnt;
struct node
{
int v;
int w;
node *next;
}pool[MAXN << 1], *head[MAXN << 1]; void addedge(int u, int v, int w)
{
node *p = &pool[++ecnt], *q = &pool[++ecnt];
p->v = v, p->w = w, p->next = head[u], head[u] = p;
q->v = u, q->w = w, q->next = head[v], head[v] = q;
} void dfs(int u)
{
int v;
dfn[++Index] = u;
vis[u] = 1;
for(node *p = head[u]; p; p = p->next)
if(!vis[v = p->v])
{
dep[v] = dep[u] + 1;
dissum[v] = dissum[u] + p->w;
fa[v][0] = u;
predis[v] = p->w;
dfs(v);
}
} int LCA(int u, int v)
{
if(dep[u] < dep[v]) swap(u, v);
for(int i = 20; i >= 0; i--)
if(fa[u][i] != 0 && dep[fa[u][i]] >= dep[v])
u = fa[u][i];
if(u == v) return u;
for(int i = 20; i >= 0; i--)
if(fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
} bool check(int dis)
{
memset(treeC, 0, sizeof(treeC));
Edge_cnt = 0;
for(int i = 1; i <= m; i++)
if(distence[i] > dis)
{
++Edge_cnt;
treeC[u[i]]++;
treeC[v[i]]++;
treeC[lca[i]] -= 2;
}
for(int i = n; i >= 1; i--)
{
int t = dfn[i];
treeC[fa[t][0]] += treeC[t];
if(dis >= Max_dis - predis[t] && treeC[t] == Edge_cnt)
return true;
}
return false;
} int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n - 1; i++)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
}
dep[1] = 1, dep[0] = -1;
dfs(1);
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= n; i++)
fa[i][j] = fa[fa[i][j - 1]][j - 1];
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &u[i], &v[i]);
lca[i] = LCA(u[i], v[i]);
distence[i] = dissum[u[i]] + dissum[v[i]] - dissum[lca[i]] * 2;
Max_dis = max(Max_dis, distence[i]);
}
int ans = -1;
int l = 0, r = Max_dis;
while(l <= r)
{
int mid = (l + r) / 2;
if(check(mid)) r = mid - 1, ans = mid;
else l = mid + 1;
}
printf("%d\n", ans);
return 0;
}

题解 【luogu P2680 NOIp提高组2015 运输计划】的更多相关文章

  1. 题解——洛谷 P2680 NOIP提高组 2015 运输计划

    树上差分加上二分答案 详细题解待填坑 #include <cstdio> #include <algorithm> #include <cstring> using ...

  2. 【NOIP】提高组2015 运输计划

    [题意]n个点的树,m条链,求将一条边的权值置为0使得最大链长最小. [算法]二分+树上差分 [题解] 最大值最小化问题,先考虑二分最大链长. 对所有链长>mid的链整体+1(树上差分). 然后 ...

  3. 树型大融合——NOIP提高组2015 D1T3 【运输计划】

    下午用一个小时看了一下树上差分,打了个差分模板,A了3题,真的爽! 题目描述: 公元2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 ...

  4. 【NOIP2015提高组】运输计划

    https://daniu.luogu.org/problem/show?pid=2680 使完成所有运输计划的时间最短,也就是使时间最长的运输计划耗时最短.最大值最小问题考虑用二分答案,每次chec ...

  5. 题解 【luogu P1541 NOIp提高组2010 乌龟棋】

    题目链接 题解 题意: 有一些格子,每个格子有一定分数. 给你四种卡片,每次可以使用卡片来前进1或2或3或4个格子并拾取格子上的分数 每张卡片有数量限制.求最大分数. 分析 设\(dp[i]\)为第前 ...

  6. 题解 【luoguP1967 NOIp提高组2013 货车运输】

    题目链接 题解 题意 给你一个无向图,求两个点之间的一条路径,使路径上的最小值最大 算法:Kruskal最大生成树+倍增lca 分析 首先容易知道,答案一定在该图的最大生成树上 之后问题便转换成了树上 ...

  7. 题解【luoguP1525 NOIp提高组2010 关押罪犯】

    题目链接 题解 算法: 一个经典的并查集 但是需要用一点贪心的思想 做法: 先将给的冲突们按冲突值从大到小进行排序(这很显然) 然后一个一个的遍历它们 如果发现其中的一个冲突里的两个人在同一个集合里, ...

  8. 题解【luoguP1351 NOIp提高组2014 联合权值】

    题目链接 题意:给定一个无根树,每个点有一个权值.若两个点 \(i,j\) 之间距离为\(2\),则有联合权值 \(w_i \times w_j\).求所有的联合权值的和与最大值 分析: 暴力求,每个 ...

  9. NOIP2015_提高组Day2_3_运输计划

    这题思路很简单: 先对每个询问求距离,对距离由大到小排序, 二分最小距离,验证是否可行,验证时用差分处理: #include<iostream> #include<cstring&g ...

随机推荐

  1. 《Git学习指南》学习笔记(二)

    第三章 提交究竟是什么 每次提交都会生成一个40位的散列值.只要知道散列值,我们就可以恢复到该次提交,这个操作也被称之为检出(checkout)操作. 访问权限与时间戳 Git会保存每个文件原有的访问 ...

  2. python常用命令—windows终端查看安装包信息

    1, pip list 会将 Python 的所有安装包全部显示出来, 左边是包名, 右边是包的版本号. 2, pip show 包的名字 会将这个包的名字,版本号,包的功能说明,按装这个包的路径显示 ...

  3. kvm网络虚拟化

    网络虚拟化是虚拟化技术中最复杂的部分,学习难度最大. 但因为网络是虚拟化中非常重要的资源,所以再硬的骨头也必须要把它啃下来. 为了让大家对虚拟化网络的复杂程度有一个直观的认识,请看下图 这是 Open ...

  4. 官方文档 恢复备份指南二 Getting Started with RMAN

    本章对RMAN进行基本的熟悉和了解   1.Overview of the RMAN Environment    RMAN运行时需要的最小环境:      target database       ...

  5. es6从零学习(二):promise

    es6从零学习(二):promise 一:promise的由来 某些情况下,回调嵌套很多时,代码就会非常繁琐,会给我们的编程带来很多的麻烦,这种情况俗称——回调地狱.由此,Promise的概念就由社区 ...

  6. 20145214 《Java程序设计》第2周学习总结

    20145214 <Java程序设计>第2周学习总结 教材学习内容总结 基本类型 整数:可分为short整数.int整数.long整数. 字节:即byte类型,可表示-128~127的整数 ...

  7. 【转载】【翻译】Breaking things is easy///机器学习中安全与隐私问题(对抗性攻击)

    原文:Breaking things is easy 译文:机器学习中安全与隐私问题(对抗性攻击) 我是通过Infaraway的那篇博文才发现cleverhans-blog的博客的,这是一个很有意思的 ...

  8. Unity3d学习日记(五)

      之前用3dsmax将模型转成FBX怎么也没有办法自动导入材质到Unity3d中(试过勾选了导出嵌入媒体,没用).索性试了试c4d,发现是可行的,看来像我这种菜鸡还是更加适合用c4d.   拿zoe ...

  9. 异常--try..catch

    class Program { static void Main(string[] args) { try { object obj = null; int N = (int)obj; } catch ...

  10. 关于houghlines函数角度问题的说明

    以上是opecv reference里面的说明. Image必须是8位单通道图(可以使灰度图.二值图.边缘图等) Rho:距离分辨率,一般为1 Theta:角度分辨率,一般为CV_PI/180 Thr ...