CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)
Posted 1000suns
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)相关的知识,希望对你有一定的参考价值。
神仙题。
先考虑平方级别的暴力怎么做。
明显答案有单调性,先二分 (c)。
先最短路预处理 (dis_u) 表示 (u) 到离它最近的充电站的距离(一开始把 (1) 到 (k) 全部丢到优先队列里就行了)。
考虑当前站在 (u) 点上时,剩余的电量是 (x)。注意到由于起点是充电站,就一定有 (xle 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) 时要 (xge dis_u) 才有用,所以考虑我们会走一条边 ((u,v,w)),当且仅当 (c-dis_u-wge dis_v),即 (dis_u+dis_v+wle c)。
那么问题变成求一条从 (a) 到 (b) 的路径使得路径上每条边的 (dis_u+dis_v+w) 的最大值最小(明显是满足条件的最小的 (c))。
还不会?
右转 NOIP2013 货车运输。
如果用最小生成树或者 Kruskal 重构树,时间复杂度大概是 (O((n+m)log n+mlog m+mlog n+qlog n))。(最短路+给边排序+求树+LCA)
(顺便提个并查集的做法:询问离线下来,森林中每棵树的根记录这里面有哪些点。使用按秩合并,每个点至多被合并 (log) 次。)
Kruskal 重构树的代码
#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
",wnd[lca(u,v)]);
}
}
以上是关于CF1253F Cheap Robot(神奇思路,图论,最短路,最小生成树/Kruskal 重构树/并查集)的主要内容,如果未能解决你的问题,请参考以下文章