神仙题。

先考虑平方级别的暴力怎么做。

明显答案有单调性,先二分 \(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 重构树/并查集)的更多相关文章

  1. Luogu4768 NOI2018 归程 最短路、Kruskal重构树

    传送门 题意:给出一个$N$个点.$M$条边的图,每条边有长度和海拔,$Q$组询问,每一次询问从$v$开始,经过海拔超过$p$的边所能到达的所有点中到点$1$的最短路的最小值,强制在线.$N \leq ...

  2. 【BZOJ5415&UOJ393】归程(Kruskal重构树,最短路)

    题意:From https://www.cnblogs.com/Memory-of-winter/p/11628351.html 思路:先从1开始跑一遍dijkstra,建出kruskal重构树之后每 ...

  3. 【NOI2018】归程 题解(kruskal重构树+最短路)

    题目链接 题目大意:给定一张$n$个点$m$条边的无向图.每条边有长度和海拔.有$Q$次询问,每次给定起点$v$和当天水位线$p$,每次终点都是$1$.人可以选择坐车或走路,车只能在海拔大于水位线的路 ...

  4. bzoj3694: 最短路(树链剖分/并查集)

    bzoj1576的帮我们跑好最短路版本23333(双倍经验!嘿嘿嘿 这题可以用树链剖分或并查集写.树链剖分非常显然,并查集的写法比较妙,涨了个姿势,原来并查集的路径压缩还能这么用... 首先对于不在最 ...

  5. 图论(最短路&最小生成树)

    图论 图的定义与概念 图的分类 图,根据点数和边数可分为三种:完全图,稠密图与稀疏图. 完全图,即\(m=n^2\)的图\((m\)为边数,\(n\)为点数\()\).如: 1 1 0 1 2 1 1 ...

  6. loj2718 「NOI2018」归程[Kruskal重构树+最短路]

    关于Kruskal重构树可以翻阅本人的最小生成树笔记. 这题明显裸的Kruskal重构树. 然后这题限制$\le p$的边不能走,实际上就是要满足走最小边权最大的瓶颈路,于是跑最大生成树,构建Krus ...

  7. 洛谷P4768 [NOI2018]归程(可持久化并查集,最短路)

    闲话 一个蒟蒻,在网络同步赛上进行了这样的表演-- T2组合计数不会,T3字符串数据结构不会,于是爆肝T1 一开始以为整个地图都有车,然后写了2h+的树套树,终于发现样例过不去 然后写可持久化并查集D ...

  8. POJ 1182 食物链 [并查集 带权并查集 开拓思路]

    传送门 P - 食物链 Time Limit:1000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit  ...

  9. P1197 [JSOI2008]星球大战[并查集+图论]

    题目来源:洛谷 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球 ...

随机推荐

  1. mysql初始化/usr/local/mysql/bin/mysqld: error while loading shared libraries: libnuma.so.1: cannot open shared object file: No such file or directory

    [root@test153 ~]# /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql - ...

  2. packstack-ironic

    安装openstack Pike版本, 其它版本安装方法类似. centos7.6 packstack目前对NetworkManager 还不支持,我们修改下配置: systemctl disable ...

  3. mongodb使用_遍历列表中的元素,作为变量,循环修改mongodb中的字段

    一.问题描述: 需要将工作界面上的一些已经离职的用户状态改为失效,并备注为离职 二.需要准备/拿到手的工具/条件/数据: 1.已离职人员名单(excel格式) 2.任意mongodb工具(笔者使用的是 ...

  4. vue.set( target, key, value ) this.$set(对象获数组,要更改的具体数据,重新赋值)用法

    调用方法:Vue.set( target, key, value ) target:要更改的数据源(可以是对象或者数组) key:要更改的具体数据 value :重新赋的值 具体用法js代码: //设 ...

  5. C和C++常见误区以及问题整理

    c和c++的关系 c是面向过程的语言,c++是在c的基础上扩展的面向对象的编程语言. c++具备c的所有功能,对c的库完全兼容. c++的标准在98年确定,在那之前已经有一些库大量使用. 新标准中,推 ...

  6. Web安全测试学习笔记-DVWA-存储型XSS

    XSS(Cross-Site Scripting)大致分为反射型和存储型两种,之前对XSS的认知仅停留在如果网站输入框没有屏蔽类似<script>alert('ok')</scrip ...

  7. strlen函数 (求字符串长度函数)

    strlen函数原型在<string.h>中 #include <stdio.h> #include <string.h> int main(){ char *p= ...

  8. 【Java基础】Java中你必须知道的知识点

    目录 Java中面向对象的基础知识 1. 什么是面向对象  2. 三大基本特征和五项基本原则 3. Java的平台无关性 4. 值传递和引用传递 5. 方法重载和重写 6. 基本数据类型 7. 包装类 ...

  9. Spring Boot可执行Jar包运行原理

    目录 1. 打可执行Jar包 2. 可执行Jar包内部结构 3. JarLauncher 4. 简单总结 5. 远程调试 Spring Boot有一个很方便的功能就是可以将应用打成可执行的Jar.那么 ...

  10. React 从入门到进阶之路(一)

    在开始 React 学习之前我们先进入官网 https://react.docschina.org/ 看看官方对 React 的解释:React 是用于构建用户界面的JavaScript 库.我们只需 ...