Cheap Robot
You’re given a simple, undirected, connected, weighted graph with n nodes and m edges.
Nodes are numbered from 1 to n. There are exactly k centrals (recharge points), which are nodes 1,2,…,k.
We consider a robot moving into this graph, with a battery of capacity c, not fixed by the constructor yet. At any time, the battery contains an integer amount x of energy between 0 and c inclusive.
Traversing an edge of weight wi is possible only if x≥wi, and costs wi energy points (x:=x−wi).
Moreover, when the robot reaches a central, its battery is entirely recharged (x:=c).
You’re given q independent missions, the i-th mission requires to move the robot from central ai to central bi.
For each mission, you should tell the minimum capacity required to acheive it.
Input
The first line contains four integers n, m, k and q (2≤k≤n≤105 and 1≤m,q≤3⋅105).
The i-th of the next m lines contains three integers ui, vi and wi (1≤ui,vi≤n, ui≠vi, 1≤wi≤109), that mean that there’s an edge between nodes u and v, with a weight wi.
It is guaranteed that the given graph is simple (there is no self-loop, and there is at most one edge between every pair of nodes) and connected.
The i-th of the next q lines contains two integers ai and bi (1≤ai,bi≤k, ai≠bi).
Output
You have to output q lines, where the i-th line contains a single integer : the minimum capacity required to acheive the i-th mission.
Examples
input
10 9 3 1
10 9 11
9 2 37
2 4 4
4 1 8
1 5 2
5 7 3
7 3 2
3 8 4
8 6 13
2 3
output
12
input
9 11 3 2
1 3 99
1 4 5
4 5 3
5 6 3
6 4 11
6 7 21
7 2 6
7 8 4
8 9 3
9 2 57
9 3 2
3 1
2 3
output
38
15
给定一个联通、无向、无环图,前k个点可以充电,经过一条边花费w电,q个询问,从前k个点中选取两个点a,b。求a到b电池容量的最小值。
设
d
u
d_u
du是u点到距离u点最近的充电站的距离。
到达u点时,剩余容量为x。
如果
x
<
d
u
x<d_u
x<du,则u点不能到达任意的前k个点。
否则,
x
>
=
d
u
x>=d_u
x>=du,u点是从某个充电站过来,所以
x
<
=
C
−
d
u
x<=C-d_u
x<=C−du,因此,从u点到最近的点,再回来,能使x增大,所以,到达某点剩余的电量为
C
−
d
u
C-d_u
C−du
如果u能到达v,则
(
C
−
d
u
)
−
w
i
>
=
d
v
(C-d_u)-w_i>=d_v
(C−du)−wi>=dv即:
c
>
=
d
u
+
d
v
+
w
i
c>=d_u+d_v+w_i
c>=du+dv+wi
将
d
u
+
d
v
+
w
i
d_u+d_v+w_i
du+dv+wi视为点u,v之间的边权。
求两点之间路径上最大值的最小值。
树剖或者重构树都能做。
#include<bits/stdc++.h>
using namespace std;
char buf[1<<20],*P1=buf,*P2=buf;
#define gc() (P1==P2&&(P2=(P1=buf)+fread(buf,1,1<<20,stdin),P1==P2)?EOF:*P1++)
#define TT template<class T>inline
TT bool read(T &x){
x=0;char c=gc();bool f=0;
while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
if(f)x=-x;return 1;
}
TT bool read(T&a,T&b){return read(a)&&read(b);}
TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
typedef long long ll;
const ll MAXN=1e5+8,mod=1e9+8,inf=1ll<<50;
#define lowbit(x) (x&(-x))
struct E{
int x,y,nt;ll v;
bool operator<(const E&b)const{return v<b.v;}
}e[MAXN*6];
int head[MAXN],cnt;
inline void add(int x,int y,ll v){
e[++cnt].nt=head[x];head[x]=cnt;
e[cnt].v=v;e[cnt].x=x;e[cnt].y=y;
}
struct Node{int y,nt;}node[MAXN<<1];
int Nodehead[MAXN<<1],Nodecnt;
inline void addNode(int x,int y){
node[++Nodecnt].nt=Nodehead[x];
node[Nodecnt].y=y;
Nodehead[x]=Nodecnt;
}
int n,m,k,q;
ll dis[MAXN];
void dijkstra(){
priority_queue<pair<ll,int>>que;
for(int i=1;i<=k;++i)que.emplace(0,i);
for(int i=k+1;i<=n;++i)dis[i]=inf;
int x,y;ll v;
while(!que.empty()){
x=que.top().second;
v=-que.top().first;
que.pop();
if(dis[x]!=v)continue;
for(int i=head[x];i;i=e[i].nt){
y=e[i].y,v=e[i].v;
if(dis[y]>dis[x]+v){
dis[y]=dis[x]+v;
que.emplace(-dis[y],y);
}
}
}
}
int deep[MAXN<<1],son[MAXN<<1],fa[MAXN<<1],tot[MAXN<<1];
void dfs1(int x,int f){
deep[x]=deep[f]+1,tot[x]=1,fa[x]=f;
int max_son=-1;
for(int i=Nodehead[x];i;i=node[i].nt){
int y=node[i].y;
if(tot[y])continue;
dfs1(y,x);
tot[x]+=tot[y];
if(max_son<tot[y])
son[x]=y,max_son=tot[y];
}
}
int top[MAXN<<1];
void dfs2(int x,int tp){
top[x]=tp;
if(son[x])dfs2(son[x],tp);
else return;
for(int i=Nodehead[x];i;i=node[i].nt){
int y=node[i].y;
if(top[y])continue;
dfs2(y,y);
}
}
int lca(int x,int y){
while(top[x]^top[y]){
if(deep[top[x]]<deep[top[y]])y=fa[top[y]];
else x=fa[top[x]];
}
if(deep[x]>deep[y])return y;
return x;
}
int find(int x){return x^fa[x]?(fa[x]=find(fa[x])):x;}
ll val[MAXN<<1];
void kruskal(){
int id=n;
sort(e+1,e+1+cnt);
for(int i=0;i<n*2+2;++i)fa[i]=i;
for(int i=1;i<=cnt;++i){
int fx=find(e[i].x),fy=find(e[i].y);
if(fx^fy){
val[++id]=e[i].v;
fa[fx]=fa[fy]=id;
addNode(id,fx);
addNode(id,fy);
}
}
dfs1(id,0);
dfs2(id,id);
}
int main() {
read(n,m),read(k,q);
for(int i=0;i<m;++i){
int x,y;ll v;
read(x,y);read(v);
add(x,y,v);
add(y,x,v);
}
dijkstra();
for(int i=1;i<=n;++i)
for(int j=head[i];j;j=e[j].nt)
e[j].v+=dis[e[j].x]+dis[e[j].y];
kruskal();
while(q--){
int x,y;
read(x,y);
printf("%I64d\n",val[lca(x,y)]);
}
return 0;
}