洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)
【思路】:
根据题意可以明显看出,当所有任务都完成时的时间是最终的结果,也就是说本题要求,求出最小的最大值。
那这样的话就暗示了将答案二分,进行check。
【check方法】:
如果说当前答案为ans,每个任务设为p[i],所花费的时间是p[i].tim,所有任务p[i].tim的最大值为maxdis
那么则将符合条件p[i].tim>=ans的数量num求出来,这个数量也就是符合条件的路径的数量(一个任务在u,v之间有一个简单路径很容易理解),
然后找到一个所有路径中他们的公共边(公共边就是这个边在符合条件的p[i]中出现的次数==num的边)中最大的一个mmax,如果说
maxdis-mmax<=ans那么check返回1,使得上界变成mid-1,理由是如果最长的路减去一个此时最大的公共边比此时答案ans小,说明ans还可以
继续减小,即让最大值变得更小,反之则不能。
【寻找公共边方法】:
使用树上差分,对任务进行离线处理,定义cnt[x]是x到x的父亲gra[x][0]这条边经过的次数,在check函数中,符合p[i].tim>ans的就让cnt[p[i].u] ++, cnt[p[i].v]++, cnt[p[i].lca] -= 2
所有的任务都判断完成时,进行Dfs更新所有节点的cnt[],当cnt[x]==num && dis[x]-dis[gra[x][0]]>=mmax时更新mmax。进行完Dfs后判断maxdis-mmax与ans关系即可。
#include <bits/stdc++.h>
using namespace std; const int maxn = 3e5 + ;
const int maxm = maxn;
const int inf = 0x3f3f3f3f;
int n, m, mmax, num, ans, maxdis;
struct edge{
int to, w, next;
} ed[maxn<<];
struct plan{
int u, v, lca, tim;
plan( int u=, int v=, int lca=, int tim= ):
u(u),v(v),lca(lca),tim(tim){}
} p[maxm];
int head[maxn], tot, cnt[maxn];
int gra[maxn][], dep[maxn], dis[maxn], maxdep;
inline int read(){
int k=0, f=1;
char ch=getchar();
while( ch>''|| ch<'' ){ if( ch=='-' ) f = -; ch = getchar(); }
while( ch<='' && ch>='' ){ k = k*+ch-''; ch = getchar(); }
return k*f;
} inline void init(){
memset( head ,- ,sizeof(head) );
memset( gra, , sizeof(gra) );
maxdep = log(n)/log();
tot = ;
} inline void add( int u, int v, int w ){
ed[++tot].to = v;
ed[tot].w = w;
ed[tot].next = head[u];
head[u] = tot;
} inline void dfs_lca( int x ){ //初始化与LCA相关的数据
for( int i=; i<=maxdep; i++ ){
gra[x][i] = gra[gra[x][i-]][i-];
if( !gra[x][i] ) break;
}
for( int i=head[x]; ~i; i=ed[i].next ){
int y = ed[i].to;
if( y==gra[x][] ) continue;
dep[y] = dep[x]+;
dis[y] = dis[x]+ed[i].w;
gra[y][] = x;
dfs_lca(y);
}
} inline void dfs_diff( int x ){
for( int i=head[x]; ~i; i=ed[i].next ){
int y = ed[i].to;
if(y==gra[x][]) continue;
dfs_diff(y);
cnt[x] += cnt[y];
}
if( cnt[x]==num && mmax<dis[x]-dis[gra[x][]] ) //寻找最大的公共边
mmax = dis[x]-dis[gra[x][]];
} inline void swap( int &a, int &b ){
int t = a;
a = b;
b = t;
} inline int LCA( int x, int y ){
if(dep[x]>dep[y]) swap(x, y);
for( int i=maxdep; ~i; i-- )
if( gra[y][i]==x ) return x; //避免卡常,能return就return
else if( dep[gra[y][i]]>=dep[x] ) y = gra[y][i];
if( x==y ) return x; //避免卡常
for( int i=maxdep; ~i; i-- )
if( gra[x][i]!=gra[y][i] ){
x = gra[x][i];
y = gra[y][i];
}
if( x!=y ) x = gra[x][];
return x;
} inline int max( int a, int b ){
return a>b ? a:b;
} inline bool check( int x ){
mmax = num = ; //每次check都将mmax, num, cnt初始化为0
memset( cnt ,, sizeof(cnt) );
for( int i=; i<=m; i++ ){
if( p[i].tim<=x ) continue;
num ++;
cnt[p[i].u] ++;
cnt[p[i].v] ++;
cnt[p[i].lca] -= ;
}
dfs_diff(); //更新每个结点的cnt
return maxdis-mmax<=x;
} int main(){
n = read(); m = read(); //读取方式使用快读,此题卡常数卡的很厉害
init();
int maxe = -inf;
for( int i=; i<n; i++ ){
int u, v, w;
u = read(); v = read(); w = read();
add(u, v, w);
add(v, u, w);
maxe = max( maxe, w );
}
dep[] = ;
dis[] = ;
dfs_lca();
maxdis = -inf;
for( int i=; i<=m ;i++ ){
int u, v;
u = read(); v = read();
int lca = LCA(u, v);
p[i] = plan( u, v, lca, dis[u]+dis[v]-(dis[lca]<<) ); //储存,后续进行离线处理
maxdis = max( maxdis, p[i].tim ); //获得一条边都不是虫洞的最大值
}
int l = maxdis-maxe, r = maxdis; //这里要优化下界l,不然会超时
while( l<=r ){
int mid = (l+r)>>;
if( check(mid) ){
ans = mid;
r = mid-;
}
else l = mid+;
}
printf("%d\n", ans); return ;
}
洛谷P2680 运输计划(倍增LCA + 树上差分 + 二分答案)的更多相关文章
- 洛谷 P2680 运输计划-二分+树上差分(边权覆盖)
P2680 运输计划 题目背景 公元 20442044 年,人类进入了宇宙纪元. 题目描述 公元20442044 年,人类进入了宇宙纪元. L 国有 nn 个星球,还有 n-1n−1 条双向航道,每条 ...
- 洛谷 P2680 运输计划 解题报告
P2680 运输计划 题目背景 公元2044年,人类进入了宇宙纪元. 题目描述 公元2044年,人类进入了宇宙纪元. \(L\)国有\(n\)个星球,还有\(n-1\)条双向航道,每条航道建立在两个星 ...
- [NOIP2015] 提高组 洛谷P2680 运输计划
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...
- 洛谷P2680 运输计划 [LCA,树上差分,二分答案]
题目传送门 运输计划 Description 公元 2044 年,人类进入了宇宙纪元.L 国有 n 个星球,还有 n?1 条双向航道,每条航道建立在两个星球之间, 这 n?1 条航道连通了 L 国的所 ...
- 洛谷P2680 运输计划——树上差分
题目:https://www.luogu.org/problemnew/show/P2680 久违地1A了好高兴啊! 首先,要最大值最小,很容易想到二分: 判断当前的 mid 是否可行,需要看看有没有 ...
- 洛谷P2680 运输计划(树上差分+二分)
传送门 考虑树上乱搞 首先这是满足二分性质的,如果在某个时间可以完成工作那么比他更长的时间肯定也能完成工作 然后考虑二分,设当前答案为$mid$,如果有一条链的长度大于$mid$,那么这条链上必须得删 ...
- 洛谷 P2680 运输计划(NOIP2015提高组)(BZOJ4326)
题目背景 公元 \(2044\) 年,人类进入了宇宙纪元. 题目描述 公元\(2044\) 年,人类进入了宇宙纪元. L 国有 \(n\) 个星球,还有 \(n-1\) 条双向航道,每条航道建立在两个 ...
- 洛谷——P2680 运输计划
https://www.luogu.org/problem/show?pid=2680 题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每 ...
- 洛谷 P2680 运输计划
题目背景 公元 2044 年,人类进入了宇宙纪元. 题目描述 L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球. 小 P 掌管一家 ...
随机推荐
- STL——sort函数的实现原理
实现原理 sort结合了快速排序.堆排序.直接插入排序三种排序方法. 根据不同的数量级别以及不同情况,能自动选用合适的排序方法.当数据量较大时采用快速排序,分段递归.一旦分段后的数据量小于某个阀值,为 ...
- [LeetCode] 314. Binary Tree Vertical Order Traversal 二叉树的竖直遍历
Given a binary tree, return the vertical order traversal of its nodes' values. (ie, from top to bott ...
- [LeetCode] 52. N-Queens II N皇后问题之二
The n-queens puzzle is the problem of placing nqueens on an n×n chessboard such that no two queens a ...
- ZROI1153 【线上训练3】数个数
ZROI1153 [线上训练3]数个数 传送门 一道非常有意思的题,涵盖了各种知识点. 首先,很显然,这是个容斥.容斥可以过掉\(30pts\). 这里我们考虑容斥+DP. 我们令\(dp[i][j] ...
- Python连载28-logging设置&logger解析
一.logging模块讲解 1.函数:logging.basicConfig() 参数讲解: (1)level代表高于或者等于这个值时,那么我们才会记录这条日志 (2)filename代表日志会写在这 ...
- Visual Studio2017专业版和企业版密钥
Professional: KBJFW-NXHK6-W4WJM-CRMQB-G3CDH Enterprise: NJVYC-BMHX2-G77MM-4XJMR-6Q8QF
- Fiddler抓包工具怎么设置HTTPS抓包
最近在学习使用 Fiddler 抓包工具时遇到一个问题,Fiddler 默认只对 HTTP 协议进行抓包,如果出现下图提示,则需要进行相应设置才可以抓包HTTPS 具体步骤 ①:Tools-Optio ...
- Windbg断点调试.net程序
程序员都知道,在生产环境中,如果没有系统日志,对问题的分析将非常的困难.即使有日志,有时候也会因为日志记录的不全面,而导致问题不能分析清楚.其实,Windbg里面有Live Debug功能,正好可以借 ...
- 第八节:EF Core连接MySql数据库
一. 前提 1.安装EF Core连接MySQL的驱动,这里有两类: (1).Oracle官方出品:MySql.Data.EntityFrameworkCore (版本:8.0.17) (2).其他第 ...
- Java se课程设计详解——数据库接口类(1)
开始做课程设计的时候根本无从下手,后来查阅资料后发现是先从数据库开始的.整个课程设计需要用到的如下图,今天总结一下数据库接口! 数据库接口需要用到两个类,一个是DAO.java,另一个是propert ...