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 重构树/并查集)的主要内容,如果未能解决你的问题,请参考以下文章

CF1253F Cheap Robot

CF600 div2 F.Cheap Robot

CF24D Broken robot

CF1073C Vasya and Robot

CF24D Broken robot(高斯消元)

CF538GBerserk Robot(思维)