BZOJ4326或洛谷2680 运输计划
BZOJ原题链接
洛谷原题链接
用\(LCA\)初始化出所有运输计划的原始时间,因为答案有单调性,所以二分答案,然后考虑检验答案。
很容易想到将所有超出当前二分的答案的运输计划所经过的路径标记,在这些运输计划都经过的边中的权值最大的这条边上建立虫洞,如果能使得所有运输计划中需要时间最多的那个计划能在当前二分的答案之内完成,那么这个答案就是可行的。
然后考虑如何快速找到这些运输计划都经过的边,本质上我们要求的就是一条边被覆盖几次,所以考虑树上差分。
定义\(dif[i]\)表示点\(i\)到它父亲节点的这条边被覆盖几次,对于一个计划\((x,y)\),我们将\(dif[x]++,dif[y]++,dif[LCA(x,y)]-2\),最后将点\(i\)的子树中所有的\(dif\)累加到\(dif[i]\)即可。
不过这题挺卡常的,所以要注意常数。
- 不在求\(LCA\)的同时求经过路径长度,而是用该表达式\(dis[x]+dis[y]-dis[LCA(x,y)]\times 2\)(\(dis[x]\)表示点\(x\)到根的距离)。
- 缩小二分答案的范围,上界定为最长链的长度,即所有运输计划中需要时间最多的那个计划,下界定为最长链减去这条链上权值最大的边。
- 计算\(dif\)不用\(dfs\),而是在初始化倍增\(LCA\)的时候求出时间戳,然后枚举时间戳来累加并判断。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 3e5 + 10;
const int M = 19;
struct ts {
int x, y, t, po;
};
ts a[N];
int fi[N], di[N << 1], ne[N << 1], da[N << 1], f[N][M], g[N], dif[N], dis[N], de[N], dfn[N], l, gn, n, m, ti;
inline int re()
{
int x = 0;
char c = getchar();
bool p = 0;
for (; c < '0' || c > '9'; c = getchar())
p |= c == '-';
for (; c >= '0' && c <= '9'; c = getchar())
x = x * 10 + c - '0';
return p ? -x : x;
}
inline void add(int x, int y, int z)
{
di[++l] = y;
da[l] = z;
ne[l] = fi[x];
fi[x] = l;
}
inline void sw(int &x, int &y)
{
int z = x;
x = y;
y = z;
}
inline int maxn(int x, int y)
{
return x > y ? x : y;
}
bool comp(ts x, ts y)
{
return x.t > y.t;
}
void dfs(int x)
{
int i, y;
dfn[++ti] = x;
for (i = 1; i <= gn; i++)
{
f[x][i] = f[f[x][i - 1]][i - 1];
if (!f[x][i])
break;
}
for (i = fi[x]; i; i = ne[i])
if ((y = di[i]) ^ f[x][0])
{
f[y][0] = x;
dis[y] = dis[x] + (g[y] = da[i]);
de[y] = de[x] + 1;
dfs(y);
}
}
int lca(int x, int y)
{
int i;
if (de[x] > de[y])
sw(x, y);
for (i = gn; ~i; i--)
if (de[f[y][i]] >= de[x])
y = f[y][i];
if (!(x ^ y))
return x;
for (i = gn; ~i; i--)
if (f[x][i] ^ f[y][i])
{
x = f[x][i];
y = f[y][i];
}
return f[x][0];
}
int fin(int x, int y, int z)
{
int ma = 0;
for (; x ^ z; x = f[x][0])
ma = maxn(ma, g[x]);
for (; y ^ z; y = f[y][0])
ma = maxn(ma, g[y]);
return ma;
}
bool judge(int mid)
{
int i, k = a[1].t - mid, o = 0, x;
memset(dif, 0, sizeof(dif));
for (i = 1; i <= m; i++)
{
if (a[i].t <= mid)
break;
dif[a[i].x]++;
dif[a[i].y]++;
dif[a[i].po] -= 2;
o++;
}
if (!o)
return true;
for (i = n; i; i--)
{
x = dfn[i];
dif[f[x][0]] += dif[x];
if (!(dif[x] ^ o) && g[x] >= k)
return true;
}
return false;
}
int main()
{
int i, x, y, z, l, r, mid;
n = re();
m = re();
for (i = 1; i < n; i++)
{
x = re();
y = re();
z = re();
add(x, y, z);
add(y, x, z);
}
gn = log2(n);
de[1] = 1;
dfs(1);
for (i = 1; i <= m; i++)
{
a[i].x = re();
a[i].y = re();
a[i].po = lca(a[i].x, a[i].y);
a[i].t = dis[a[i].x] + dis[a[i].y] - (dis[a[i].po] << 1);
}
sort(a + 1, a + m + 1, comp);
r = a[1].t;
l = r - fin(a[1].x, a[1].y, a[1].po);
while (l < r)
{
mid = (l + r) >> 1;
if (judge(mid))
r = mid;
else
l = mid + 1;
}
printf("%d", r);
return 0;
}
BZOJ4326或洛谷2680 运输计划的更多相关文章
- 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)
P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...
- 洛谷 P2680 运输计划(NOIP2015提高组)(BZOJ4326)
题目背景 公元 \(2044\) 年,人类进入了宇宙纪元. 题目描述 公元\(2044\) 年,人类进入了宇宙纪元. L 国有 \(n\) 个星球,还有 \(n-1\) 条双向航道,每条航道建立在两个 ...
- 洛谷——P2680 运输计划
https://www.luogu.org/problem/show?pid=2680 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每 ...
- [NOIP2015] 提高组 洛谷P2680 运输计划
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...
- 洛谷 P2680 运输计划 解题报告
P2680 运输计划 题目背景 公元2044年,人类进入了宇宙纪元. 题目描述 公元2044年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道,每条航道建立在两个星 ...
- 洛谷P2680 运输计划 [LCA,树上差分,二分答案]
题目传送门 运输计划 Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n?1 条双向航道,每条航道建立在两个星球之间, 这 n?1 条航道连通了 L 国的所 ...
- 洛谷 P2680 运输计划
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...
- 洛谷P2680 运输计划
大概就是二分+树上差分... 题意:给你树上m条路径,你要把一条边权变为0,使最长的路径最短. 最大的最小,看出二分(事实上我并没有看出来...) 然后二分k,对于所有大于k的边,树上差分求出最长公共 ...
- 洛谷P2680运输计划
传送门啦 要求的就是,把树上的一条边的权值设为0之后,所有路径中的最大值的最小值. 首先二分最大值,假设某次二分的最大值为x,我们首先找出所有大于x的路径(也就是我们需要通过改权缩短的路径),并把路径 ...
随机推荐
- 学习JS的心路历程-参数传递方式(上)
很多人认为JS的传递方式是值是Call by value, 物件及数组是Call by Reference.甚至还有人宣称其实JS是Call by sharing,那到底是哪一个呢? 这两天我们一一来 ...
- SQL数据库优化
1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- JAVA语言 第四周
oh my god! 说实话,上周的目标没有完成. 这一周过的太随便了,比刚放假时候的热情减少的太多了. 具体干了啥,就不说了吧.好像什么完整的事都没有干~~~~~ 不过一直在完善代码,已经能实现部分 ...
- 解决python3.6的UnicodeEncodeError: 'gbk' codec can't encode character '\xbb' in position 28613: illegal multibyte sequence
这是python3.6的print()函数自身有限制,不能完全打印所有的unicode字符. 主要的是windows下python的默认编码不是'utf-8',改一下python的默认编码成'utf- ...
- xlwt使用
xlwt引入xlwt,import xlwt 新建工作簿,xlsx = xlwt.Workbook( encoding="utf-8" ),参数:设置编码为utf-8 添加工作表, ...
- day14 迭代器和生成器
1.迭代器 名词解释 什么是迭代:迭代是一个重复过程,但是每次重复都是基于上一次的结果而继续的 #下列循环只是单纯的重复,没有意义 while True: print(1) #基于索引的迭代取值 l ...
- oracle 调试数据库
转载:https://www.cnblogs.com/liuqiyun/p/6589814.html 工具/原料 PL\SQL Oracle 方法/步骤 首先在PL/SQL的左侧资源栏中展 ...
- Centos7在虚拟机中扩展磁盘空间
说明 情况:已经在VirtualBox虚拟机创建了一个磁盘并已经装好了系统,发现磁盘空间太小,需要再添加一个磁盘的大小.或者说Centos7系统需要扩展磁盘空间. 步骤 1.VirtualBox新建磁 ...
- C++中的构造函数
C++中的构造函数可以分为4类: (1)默认构造函数.以Student类为例,默认构造函数的原型为 Student()://没有参数 (2)初始化构造函数 Student(int num,int ag ...
- TOJ 3973 Maze Again && TOJ 3128 简单版贪吃蛇
TOJ3973传送门:http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=3973 时间限制(普通 ...