CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)
神仙题。
先考虑平方级别的暴力怎么做。
明显答案有单调性,先二分 \(c\)。
先最短路预处理 \(dis_u\) 表示 \(u\) 到离它最近的充电站的距离(一开始把 \(1\) 到 \(k\) 全部丢到优先队列里就行了)。
考虑当前站在 \(u\) 点上时,剩余的电量是 \(x\)。注意到由于起点是充电站,就一定有 \(x\le c-dis_u\)(考虑最后一个走到的充电站沿最短路走到这)
如果 \(x<dis_u\),因为终点是充电站,肯定不可能再到终点。
否则就可以走到最近的充电站再回来,\(x\) 就可以变成 \(c-dis_u\)。前面也推过不可能变得更大。
于是就可以直接 DFS 了。
void dfs(int u,ll x){
if(x<0) return;
vis1[u]=true; //走到过这个点
if(x<dis[u]) return;
vis2[u]=true; //走到过这个点并且电量大于dis[u]
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(vis2[v]) return;
dfs(v,c-dis[u]-w[i]);
}
}
怎么搞快点?
由于走到 \(u\) 时要 \(x\ge dis_u\) 才有用,所以考虑我们会走一条边 \((u,v,w)\),当且仅当 \(c-dis_u-w\ge dis_v\),即 \(dis_u+dis_v+w\le c\)。
那么问题变成求一条从 \(a\) 到 \(b\) 的路径使得路径上每条边的 \(dis_u+dis_v+w\) 的最大值最小(明显是满足条件的最小的 \(c\))。
还不会?
右转 NOIP2013 货车运输。
如果用最小生成树或者 Kruskal 重构树,时间复杂度大概是 \(O((n+m)\log n+m\log m+m\log n+q\log n)\)。(最短路+给边排序+求树+LCA)
(顺便提个并查集的做法:询问离线下来,森林中每棵树的根记录这里面有哪些点。使用按秩合并,每个点至多被合并 \(\log\) 次。)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=600060;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=0,f=0;
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
struct node{
ll d;
int id;
bool operator<(const node &nd)const{return d>nd.d;}
};
struct edge{
int u,v;
ll w;
bool operator<(const edge &e)const{return w<e.w;}
}e[maxn];
int n,m,k,q,el,head[maxn],to[maxn],nxt[maxn],w[maxn],u_fa[maxn];
int cnt,el2,head2[maxn],to2[maxn],nxt2[maxn],fa[maxn],sz[maxn],son[maxn],top[maxn],dep[maxn];
ll wnd[maxn],dis[maxn];
priority_queue<node> pq;
inline void add(int u,int v,int w_){
to[++el]=v;nxt[el]=head[u];head[u]=el;w[el]=w_;
}
inline void add2(int u,int v){
to2[++el2]=v;nxt2[el2]=head2[u];head2[u]=el2;
}
int getfa(int x){
return x==u_fa[x]?x:u_fa[x]=getfa(u_fa[x]);
}
void dfs1(int u,int f){
sz[u]=1;
dep[u]=dep[fa[u]=f]+1;
for(int i=head2[u];i;i=nxt2[i]){
int v=to2[i];
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int topf){
top[u]=topf;
if(son[u]) dfs2(son[u],topf);
for(int i=head2[u];i;i=nxt2[i]){
int v=to2[i];
if(v==fa[u] || v==son[u]) continue;
dfs2(v,v);
}
}
int lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int main(){
n=read();m=read();k=read();q=read();
FOR(i,1,m){
int u=read(),v=read(),w=read();
add(u,v,w);add(v,u,w);
e[i]=(edge){u,v,w};
}
MEM(dis,0x3f);
FOR(i,1,k) pq.push((node){dis[i]=0,i});
while(!pq.empty()){
ll d=pq.top().d;
int u=pq.top().id;
pq.pop();
if(d!=dis[u]) continue;
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(dis[v]>d+w[i]) pq.push((node){dis[v]=d+w[i],v});
}
}
FOR(i,1,m) e[i].w+=dis[e[i].u]+dis[e[i].v];
sort(e+1,e+m+1);
FOR(i,1,2*n) u_fa[i]=i;
cnt=n;
FOR(i,1,m){
int u=e[i].u,v=e[i].v;
ll w=e[i].w;
u=getfa(u);v=getfa(v);
if(u==v) continue;
u_fa[u]=u_fa[v]=++cnt;
wnd[cnt]=w;
add2(cnt,u);add2(cnt,v);
}
dfs1(cnt,0);dfs2(cnt,cnt);
while(q--){
int u=read(),v=read();
printf("%lld\n",wnd[lca(u,v)]);
}
}
CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)的更多相关文章
- Luogu4768 NOI2018 归程 最短路、Kruskal重构树
传送门 题意:给出一个$N$个点.$M$条边的图,每条边有长度和海拔,$Q$组询问,每一次询问从$v$开始,经过海拔超过$p$的边所能到达的所有点中到点$1$的最短路的最小值,强制在线.$N \leq ...
- 【BZOJ5415&UOJ393】归程(Kruskal重构树,最短路)
题意:From https://www.cnblogs.com/Memory-of-winter/p/11628351.html 思路:先从1开始跑一遍dijkstra,建出kruskal重构树之后每 ...
- 【NOI2018】归程 题解(kruskal重构树+最短路)
题目链接 题目大意:给定一张$n$个点$m$条边的无向图.每条边有长度和海拔.有$Q$次询问,每次给定起点$v$和当天水位线$p$,每次终点都是$1$.人可以选择坐车或走路,车只能在海拔大于水位线的路 ...
- bzoj3694: 最短路(树链剖分/并查集)
bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最 ...
- 图论(最短路&最小生成树)
图论 图的定义与概念 图的分类 图,根据点数和边数可分为三种:完全图,稠密图与稀疏图. 完全图,即\(m=n^2\)的图\((m\)为边数,\(n\)为点数\()\).如: 1 1 0 1 2 1 1 ...
- loj2718 「NOI2018」归程[Kruskal重构树+最短路]
关于Kruskal重构树可以翻阅本人的最小生成树笔记. 这题明显裸的Kruskal重构树. 然后这题限制$\le p$的边不能走,实际上就是要满足走最小边权最大的瓶颈路,于是跑最大生成树,构建Krus ...
- 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)
闲话 一个蒟蒻,在网络同步赛上进行了这样的表演-- T2组合计数不会,T3字符串数据结构不会,于是爆肝T1 一开始以为整个地图都有车,然后写了2h+的树套树,终于发现样例过不去 然后写可持久化并查集D ...
- POJ 1182 食物链 [并查集 带权并查集 开拓思路]
传送门 P - 食物链 Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u Submit ...
- P1197 [JSOI2008]星球大战[并查集+图论]
题目来源:洛谷 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球 ...
随机推荐
- STM32-24位AD7799驱动之手册代码详解,支持模拟SPI和硬件SPI
1.AD7799介绍 AD7799结构图如下所示: 其中REFIN参考电压建议为2.5V, REFIN电压低于0.1V时,则差分输入ad值就无法检测了,如下图所示: 注意: 如果REG_CONFIG的 ...
- 使用Visual Studio Code进行远程开发
微软的VS code能够适应不同开发环境,提供对多种语言的支持,使得使用VS code开发变得很流行了.因为各种原因(比如在本地设置开发环境困难,或者繁琐,或者开发环境没有图形界面),我们可能需要远程 ...
- oracle数据库system表空间增长过大的问题
网上些解决方法,就是关闭审计,之前也有同事推荐这样,下面就是关闭审计的步骤. VALUE=DB即审计开启,改成FALSE即可. SQL> show parameter audit_trail; ...
- asp.net实现SQL2005的通知数据缓存
首先第一步是确保您的 Service Broker 已经激活,激活 Service Broker (Transact-SQL)如下: USE master ; GO ALTER DATABASE Yo ...
- Python+Unittest+Requests+PyMysql+HTMLReport 接口自动化框架
整体框架使用的是:Python+Unittest+Requests+PyMysql+HTMLReport 多线程并发模式 主要依赖模块 Unittest.Requests.PyMysql.HTMLR ...
- pycharm中全局搜索ctrl+shift+F快捷键无反应原因和解决
全局搜索快捷键无反应原因:搜狗输入法占用的ctrl+shift+F快捷键,简繁切换的快捷键.在搜狗输入法中将此项取消.
- ArrayList和LinkedList介绍
java.util.ArrayList集合的数据存储结构是数组,且是多线程,元素增删慢,查找快, 由于日常使用开发大多数为查询数据,遍历数据,所以ArrayList是最常用的集合.上一节已写了. ja ...
- RobotFramework不同版本优劣势
一.RIDE 1.5.2.1 1. 安装: pip install robotframework-ride==1.5.2.1 2. 优点: 此版本是RIDE发布以来最为稳定的版本,使用性能上也较为流畅 ...
- Java Virtual Machine (JVM), Difference JDK, JRE & JVM – Core Java
By Chaitanya Singh | Filed Under: Learn Java Java is a high level programming language. A program wr ...
- stars-one的原创工具——APK签名验证破解工具
ASCTool APk签名验证破解工具 APK Signature Crack Tool 本工具只对那些仅通过 PackageManager.getPackageInfo().signatures 来 ...