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的路径(也就是我们需要通过改权缩短的路径),并把路径 ...
随机推荐
- git 先建立本地分支,再传给线上库
cd 进入本地一个文件夹 git clone 文件下来 进入右下角 develop分支(remote braches) 新建分支 (check out) a 把新分支 a 传上线上 新建一个对立 ...
- c3 新特性
渐变 线性渐变 .line { height: 100px; /*线性渐变语法*/ background-image: linear-gradient( to right,/* ...
- webpack相关配置
cd 项目文件夹 npm init -y npm install jquery -S //生成node_modules 下载好jquery 创建webpack.config.js module.exp ...
- vue 父组件中的数据如何传递给子组件
父组件:<template> <div id="app"> <img src="./assets/logo.png"> &l ...
- AlertDialog 无法去掉自带的白边
项目中开始采用AlertDialog ,根据要求要显示加圆角.但是设置圆角的背景后,会存在白边. 按网上提示的设置透明的背景都不可以. 最后采用Dialog.
- Spark Streaming之五:Window窗体相关操作
SparkStreaming之window滑动窗口应用,Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作.每次掉落在窗口内的RDD的数据,会被聚 ...
- VSC KeyNote
[VSC KeyNote] 1.前后跳转. Alt + LeftArrow, Alt + RightArrow 2.缩进问题. vsc默认缩进为4,但js代码里缩进依旧是2. 因为vscode默认启用 ...
- 读取excel表格以及生成自动化报告
数据库读取 标签(空格分隔): 数据库读取 读excel数据xlrd 当登录的账号有多个的时候,我们一般用excel存放测试数据,本节课介绍,python读取excel方法,并保存为字典格式. 1.先 ...
- GreenDao-自定义SQL查询-拼接多个查询条件-AndroidStudio
//获取本地Pad(离线工作票列表) public static List<WTDetailTableBean> getPadWTList(String token, String use ...
- IDEA中配置JUnit单元测试
参考安装教程:https://www.jianshu.com/p/c37753b6dbd6 如果想用junit4的话,需要在pom.xml中配置. 需要安装JUnitGenerator V2.0插件, ...