洛谷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 掌管一家 ...
随机推荐
- [LeetCode] 119. Pascal's Triangle II 杨辉三角之二
Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle. Note t ...
- WebAPI 使用控制台启动
using System; using System.Web.Http; using System.Web.Http.SelfHost; namespace UAC_OAuth2Center { pu ...
- JavaScript 系列--JavaScript一些奇淫技巧的实现方法(三)数字取整,数组求和
一.前言 简短的sleep函数,获取时间戳:https://www.mwcxs.top/page/746.html 数字格式化 1234567890 --> 1,234,567,890:argr ...
- RICOH C4502彩色打印机取消双面打印功能
参考下面步骤:
- Zookeeper原理图
- Spring AOP环绕异常影响的报错
最近遇到一个问题,异常是: java.lang.ClassCastException: org.springframework.http.ResponseEntity cannot be cast t ...
- PDF提取图片(错误纠正)
有个任务需要抽取pdf中的图片,于是找了一个例子但是有错误,仅此记录下 错误1. AttributeError: 'Document' object has no attribute 'getObje ...
- sql server删除重复记录只保留一条
今天遇到一个历史导入数据重复的问题,于是要删除重复的记录,一开始想用子查询的方式找到要删除记录的id删除,后来发现DELETE语句可以直接用外连接,这样更加简单,效率也更高. delete sys_p ...
- 二、hexo+github搭建个人博客的简单使用
使用hexo+github搭建一个可以外网访问的个人博客,此文用于记录博客初级的使用方法. 新建-编写-生成-部署文章的全过程 1.使用cmd完成 打开命令提示符[win+r输入cmd] 切换到自己本 ...
- 【07】Jenkins:流水线(Pipeline)
写在前面的话 个人认为 Pipeline 在 Jenkins 中算是一个优化性功能,它能够将我们的构建服务的整个过程流程化,这意味着当我们在执行到某一步的时候,可以添加询问,提示我们是否继续运行下一步 ...