Codeforces 1253F - Cheap Robot(最短路+並查集/Kruskal樹)

題目大意

n點m邊無向圖,k個關鍵點,q個詢問(a,b)。問從a到b需要的最小容量c是多少。保證a,b是關鍵點。你能量池最多有c能量,每次走邊消耗邊權那麼多的能量。在關鍵點會補滿能量。每次詢問需要的最少能量。
k,n1e5,q,m3e5k,n\le1e5,q,m\le 3e5

解題思路

以所有關鍵點爲源求一遍多源最短路,然後對於一個點uu,如果當前能量x<dis[u]x < dis[u],肯定到不了,如果x>=dis[u]x >= dis[u],那麼xx應該是cdis[u]\le c-dis[u]的。又因爲x>=dis[u]x >= dis[u]所以可以跑到那個最近的關鍵點又回來,所以x每個點u的能量可以保持在cdis[u]c-dis[u]u>vu->v可以走需要cdis[u]w>=dis[v]c-dis[u]-w >= dis[v],轉換成dis[u]+dis[v]+wcdis[u]+dis[v]+w\le c。以dis[u]+dis[v]+wdis[u]+dis[v]+w爲新邊權建立新圖。
問題就變成從一個點到另一個點經過的路徑上的最大值最小可以是多少。
兩種做法:
1.離線做法 把邊按權值排序之後進行並查集。詢問掛在點上。按需要處理的詢問數量進行啓發式合併,每個詢問最多移動loglog
2.在線做法 建立 Kruskal樹之後進行樹上倍增求lca的點權

離線做法:

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define P pair<ll, int>
using namespace std;
const int maxn = 3e5 + 50;
struct edge{
    int u ,v , nxt;
    ll w;
    bool operator < (const edge &a)const{return w < a.w;}
}e[maxn*2];
int cnt = 0;
int head[maxn];
void add(int u, int v, ll w){
    e[cnt] = (edge){u, v, head[u], w};
    head[u] = cnt++;
}
int n, m, k, Q;
priority_queue<P, vector<P>, greater<P> > q;
ll dis[maxn];
void dij(){
    while(q.size()){
        P temp = q.top();q.pop();
        int u = temp.second;
        if(dis[u] < temp.first) continue;
        for(int i = head[u]; ~i; i = e[i].nxt){
            int v = e[i].v; ll w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push(P(dis[v], v));
            }
        }
    }
}
void init(){
    memset(head, -1, sizeof head);
    cin>>n>>m>>k>>Q;
    for(int i = 0; i < m; ++i){
        int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
        add(u, v, w); add(v, u, w);
    }
    memset(dis, 0x3f, sizeof dis);
    for(int i = 1; i <= k; ++i){
        dis[i] = 0; q.push(P(0, i));
    }dij();
    int tp = 0;
    for(int i = 0; i < cnt; i += 2){
        e[tp] = e[i];
        e[tp++].w += dis[e[i].u]+dis[e[i].v];
    }
    cnt = tp;
}
ll ans[maxn*5];
struct node{int v, id;};
vector<node> g[maxn];
int fa[maxn];
int fnd(int x){
    if(x == fa[x]) return x;
    return fa[x] = fnd(fa[x]);
}
void link(int u, int v, ll w){
    u = fnd(u); v = fnd(v);
    if(u == v) return;
    if(g[u].size() > g[v].size()) swap(u, v);
    for(int i = 0; i < g[u].size(); ++i){
        int x = g[u][i].v;
        int id = g[u][i].id;
        if(fnd(x) == v)
            ans[id] = w;
        else
            g[v].push_back(g[u][i]);
    }
    fa[u] = v;
    g[u].clear();//g[u].shrink_to_fit(); return;
}
void sol(){
    for(int i = 1; i <= n; ++i) fa[i] = i;
    for(int i = 0; i < Q; ++i){
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back((node){v, i});
        g[v].push_back((node){u, i});
    }
    sort(e, e+cnt);
    for(int i = 0; i < cnt; ++i) link(e[i].u, e[i].v, e[i].w);
    for(int i = 0; i < Q; ++i) {
        printf("%lld\n", ans[i]);
    }
}
int main()
{
    init();
    sol();
}

在線做法:

#include<bits/stdc++.h>
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define P pair<ll, int>
using namespace std;
const int maxn = 3e5 + 50;
struct edge{
    int u ,v , nxt;
    ll w;
    bool operator < (const edge &a)const{return w < a.w;}
}e[maxn*2];
int cnt = 0;
int head[maxn];
void add(int u, int v, ll w){
    e[cnt] = (edge){u, v, head[u], w};
    head[u] = cnt++;
}
int n, m, k, Q;
priority_queue<P, vector<P>, greater<P> > q;
ll dis[maxn];
void dij(){
    while(q.size()){
        P temp = q.top();q.pop();
        int u = temp.second;
        if(dis[u] < temp.first) continue;
        for(int i = head[u]; ~i; i = e[i].nxt){
            int v = e[i].v; ll w = e[i].w;
            if(dis[v] > dis[u] + w){
                dis[v] = dis[u] + w;
                q.push(P(dis[v], v));
            }
        }
    }
}
void init(){
    memset(head, -1, sizeof head);
    cin>>n>>m>>k>>Q;
    for(int i = 0; i < m; ++i){
        int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
        add(u, v, w); add(v, u, w);
    }
    memset(dis, 0x3f, sizeof dis);
    for(int i = 1; i <= k; ++i){
        dis[i] = 0; q.push(P(0, i));
    }dij();
    int tp = 0;
    for(int i = 0; i < cnt; i += 2){
        e[tp] = e[i];
        e[tp++].w += dis[e[i].u]+dis[e[i].v];
    }
    cnt = tp;
}
ll ans[maxn];
int fa[maxn*2];
int fnd(int x){
    if(x == fa[x]) return x;
    return fa[x] = fnd(fa[x]);
}
int tot;
vector<int> g[maxn];
ll val[maxn];
int f[maxn][20], dep[maxn];
void get_mst(){
    tot = n;
    for(int i = 0; i <cnt; ++i){
        int u = e[i].u; int v = e[i].v;
        u = fnd(u); v = fnd(v); if(u == v) continue;
        fa[u] = fa[v] = ++tot; fa[tot] = tot; val[tot] = e[i].w;
        g[tot].push_back(v); f[v][0] = tot;
        g[tot].push_back(u); f[u][0] = tot;
    }
}
void dfs(int u){
    for(int i = 0; i+1 < 20; ++i) f[u][i+1] = f[f[u][i]][i];
    for(int i = 0; i < g[u].size(); ++i) dep[g[u][i]] =dep[u]+1, dfs(g[u][i]);
}
int lca(int u, int v){
    if(dep[u] > dep[v]) swap(u, v);
    int d = dep[v] - dep[u]; for(int i = 19; i >= 0; --i) if(d>>i&1) v = f[v][i];
    if(u == v) return u;
    for(int i = 19; i >= 0; --i){
        if(f[u][i] == f[v][i]) continue;
        u = f[u][i]; v = f[v][i];
    }return f[u][0];
}
void sol(){
    for(int i = 1; i <= n; ++i) fa[i] = i;
    sort(e, e+cnt);
    get_mst();
    dfs(tot);
    while(Q--){
        int u, v; scanf("%d%d", &u, &v);
        printf("%lld\n", val[lca(u,v)]);
    }
}
int main()
{
    init();
    sol();
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章