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的路径(也就是我们需要通过改权缩短的路径),并把路径 ...
随机推荐
- 虚拟机 安装 CentOS7
初次接触CentOS,最好是在虚拟机中安装: 因为CentOS的安装选项有很多,不理解的情况下千万不要在物理机上尝试: 不然可能出现这种情况:安装好以后,只有黑色的屏幕,只能在里面敲命令:这对于新手来 ...
- redis 启动
C:\Users\Administrator>cd c:\ c:\>cd redis-2.6 c:\redis-2.6>redis-server.exe redis.conf 测试r ...
- webpack-manifest-plugin
[webpack-manifest-plugin] Webpack plugin for generating an asset manifest. This will generate a mani ...
- metasploit framework(一):基本使用
它位于/usr/share/metasploit-framework 进入到modules目录,有六大模块 exploits:系统漏洞利用的流程,对系统漏洞注入一些特定的代码,使其覆盖程序执行寄存器, ...
- 执行SDK的aapt报错./aapt: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./aapt)
问题| 执行SDK下的aapt报错./aapt: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./aapt) ../ ...
- Excel图标布局,图表样式,图标元素
一.图标布局----图表元素的增删改 * 快速布局: 更改图表的整体布局,主要是图表标题,坐标轴,图例,网格线 * 操作如下: 选中数据源,Ctrl+Q 出现图表,选中图表,在上方选择设计, 共有10 ...
- android 区分wifi是5G还是2.4G(转)
http://bbs.csdn.net/topics/391033966?page=1 我一开始看这帖子,找不到答案,为了后来的人,我来回复吧.WifiManager wifiManager = (W ...
- php抓取股票数据
public function stock(){ $curl = new Curl(); $curl->setUserAgent('Mozilla/5.0'); $curl->get('h ...
- 与服务器同步工程(expect脚本)
先看下我实际用的例子: #!/usr/bin/expect spawn rsync -vazu ssh-src/src wayne@192.168.5.2:~/projects/ expect &qu ...
- 善于利用python中的os模块
作为一个程序猿,平时善于利用python中的os模块进行路径等操作,会省去很多麻烦,下面总结一下我平时经常用到的方法: import os os.getcwd() # 获取当前文件所在的目录 os.p ...