Description
给你一张 N 个点m条边的无向连通图,图中有 k 个充电中心。
一个机器人在图中行走,假设机器人的电池容量为 c,则任何时刻,机器人的电量 x 都必须满足 0 <= x <= c 。(机器人到达充电中心时可以充满电)
有q个询问,每次询问机器人要从a点到达b点,电池容量至少为多少,各个询问相互独立。
Solution
奇妙技巧+1
建议参考:这里
直接搞是绝对八星的。
因为我们要使路径中经过的边的权值最大值最小,即我们需要频繁地在充电中心之间移动以充电。也就是说为了使最大值最小,我们经过任意一条边时必然以离这条边最近的两个充电中心作为起点和终点。
设点x离最近的充电中心的距离为
d
i
s
x
dis_x
disx。
则对于边(x,y,z)来说,它造成的贡献是以最近的两个充电中心为起、终点的一条通路,耗费为
d
i
s
x
+
z
+
d
i
s
y
dis_x+z+dis_y
disx+z+disy(x,y为端点,z为该边花费)。
即我们可以将原图简化成只有k个充电中心和每条边对其最近的两个充电中心a,b贡献的通路(a,b,c)(c为权值)。
这样就可以简化原图了。
接下来对于q个询问(a,b),我们将所有通路以c为关键字排序,离线一条一条将通路加入空图内,判断在加上新通路有哪些询问满足条件记录答案即可。
在这个过程中可以采用按秩合并与kruskal重构树,这里代码给出的是按秩合并。
Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct data{
int y,z,nxt;
}e[600010];
struct edge{
int x,y;
ll z;
}a[300010];
struct qwq{
ll dis;
int x;
};
struct que{
int x,y,id;
}b[300010];
vector<que>v[200010];
bool operator <(const qwq &u,const qwq &v){
return u.dis>v.dis;
}
ll ans[300010];
ll dis[200010];
int siz[200010];
int head[200010];
bool vis[200010];
int f[200010];
priority_queue<qwq>q;
int n,m,k,Q,cnt;
void add(int x,int y,ll z){
cnt++;
e[cnt].y=y;
e[cnt].z=z;
e[cnt].nxt=head[x];
head[x]=cnt;
}
bool cmp(edge x,edge y){
return x.z<y.z;
}
int find(int x){
return x!=f[x]?f[x]=find(f[x]):x;
}
void dijkstra(){
for(int i=1;i<=k;i++){
q.push((qwq){0,i});
dis[i]=0;
}
while(!q.empty()){
qwq x=q.top();
q.pop(),vis[x.x]=0;
for(int i=head[x.x];i;i=e[i].nxt){
int y=e[i].y,z=e[i].z;
if(dis[y]>dis[x.x]+z){
dis[y]=dis[x.x]+z;
if(!vis[y]){
q.push((qwq){dis[y],y});
vis[y]=true;
}
}
}
}
//for(int i=1;i<=n;i++)
//cout<<"dis["<<i<<"]:"<<dis[i]<<endl;
//cout<<endl;
}
int main(){
int x,y,z;
scanf("%d%d%d%d",&n,&m,&k,&Q);
for(int i=1;i<=n;i++){
dis[i]=1e17;
f[i]=i,siz[i]=1;
}
for(int i=1;i<=m;i++){
scanf("%d%d%lld",&a[i].x,&a[i].y,&a[i].z);
add(a[i].x,a[i].y,a[i].z);
add(a[i].y,a[i].x,a[i].z);
}
dijkstra();
for(int i=1;i<=m;i++)
a[i].z+=dis[a[i].x]+dis[a[i].y];//,cout<<i<<" "<<a[i].z<<endl;
sort(a+1,a+m+1,cmp);
for(int i=1;i<=Q;i++){
b[i].id=i;
scanf("%d%d",&b[i].x,&b[i].y);
v[b[i].x].push_back(b[i]);
v[b[i].y].push_back(b[i]);
}
for(int i=1;i<=m;i++){
int x=a[i].x,y=a[i].y;
ll z=a[i].z;
int fx=find(x),fy=find(y);
if(fx==fy) continue;
if(siz[fx]<siz[fy]) swap(fx,fy);
f[fy]=fx,siz[fx]+=siz[fy];
for(int j=0;j<v[fy].size();j++){
if(find(v[fy][j].x)==find(v[fy][j].y)&&!ans[v[fy][j].id])
ans[v[fy][j].id]=z;//,cout<<"shit\n";
else v[fx].push_back(v[fy][j]);
}
}
for(int i=1;i<=Q;i++)
printf("%lld\n",ans[i]);
}