题目
题意
给有权无向图,有k个中心点,油耗为距离,每次到中心点可以加油,给q个询问:从中心a走到中心b,如果每次加油数相同,每次最少加多少油保证可以从a到b。
思路
可以把中心点连超级源点,然后跑最短路,在最短路树上枚举每一条边构建新图(只含中心点的图)。
然后可以在新图上跑最小生成树,构建新新图(因为只要保证经过的边权最大值最小)
然后就是在新新图上进行q个询问,那么lca暴力搞就可以。
其实可以不用lca,带秩并查集可以解决(我不会)
/*
Author: Rshs
Time: 2019-11-17-22.06
*/
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-8;
const LL mod = 1e9+7;
const int MXN = 2e5;
const int MXLOG = 20;
vector<pair<LL,int> >g[MXN],G[MXN];
LL d[MXN];
int dfg[MXN],sour[MXN];
int fa[MXN];
int found(int x) {if(x==fa[x])return x;return fa[x]=found(fa[x]);}
int bei[MXN][MXLOG],de[MXN];
LL val[MXN][MXLOG];
void dfs(int u,int p){//所有都是向上走2^k步 所代表的含义
for(auto i:G[u]) {
if(i.SE!=p){
de[i.SE]=de[u]+1;bei[i.SE][0]=u;val[i.SE][0]=i.FI;
dfs(i.SE,u);
}
}
}
void initLCA(int nn){
bei[1][0]=-1;de[1]=0;dfs(1,-1);
for(int k=0;k<MXLOG-1;k++){ //-1!!!
for(int v=1;v<=nn;v++){
if(bei[v][k]<0)bei[v][k+1]=-1;
else bei[v][k+1]=bei[bei[v][k]][k],val[v][k+1]=max(val[v][k],val[bei[v][k]][k]);
}
}
}
LL query(int u,int v){
if(de[u]>de[v]) swap(u,v);
LL re=-1;
for(int k=0;k<MXLOG;k++){
if((de[v]-de[u])>>k&1)
re=max(re,val[v][k]),v=bei[v][k];
}
if(u==v) return re;
for(int k=MXLOG-1;k>=0;k--){
if(bei[u][k]!=bei[v][k]){
re=max(re,val[v][k]),re=max(re,val[u][k]);
u=bei[u][k],v=bei[v][k];
}
}
re=max(re,val[u][0]);re=max(re,val[v][0]);
return re;
}
int main(){
int n,m,k,q;cin>>n>>m>>k>>q;
for(int i=1;i<=m;i++){
int su,sv,sw;scanf("%d%d%d",&su,&sv,&sw);
g[su].push_back(MP(sw,sv));g[sv].push_back(MP(sw,su));
}
priority_queue<pair<LL,int> > pq;
for(int i=1;i<=n;i++) d[i]=LLONG_MAX/2;
for(int i=1;i<=k;i++) pq.push(MP(0,i)),d[i]=0,sour[i]=i;
while(!pq.empty()){
auto now=pq.top();pq.pop();
int u=now.SE;
if(dfg[u]) continue;
dfg[u]=1;
for(auto ed:g[u]){
LL dis=ed.FI+d[u];
if(dis>d[ed.SE]) continue;
d[ed.SE]=dis;sour[ed.SE]=sour[u];
pq.push(MP(-dis,ed.SE));
}
}
vector< tuple<LL,int,int> >krs;
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++){
for(auto ed:g[i]){
if(sour[i]!=sour[ed.SE]) krs.push_back(make_tuple(ed.FI+d[i]+d[ed.SE],sour[i],sour[ed.SE]));
}
}
sort(krs.begin(),krs.end());
for(auto i:krs){
int xx=found(get<1>(i));
int yy=found(get<2>(i));
if(xx==yy) continue;
fa[xx]=fa[yy];
G[get<1>(i)].push_back(MP(get<0>(i),get<2>(i)));
G[get<2>(i)].push_back(MP(get<0>(i),get<1>(i)));
}
initLCA(n);
while(q--){
int sa,sb;scanf("%d%d",&sa,&sb);
cout<<query(sa,sb)<<'\n';
}
return 0;
}