CF1051F The Shortest Statement

CF链接:CF1051F The Shortest Statement
洛谷链接:CF1051F The Shortest Statement
缝合怪,普及题
第一眼不可做,第二眼 \(N - M \le 20\) 那么考虑一个树上挂了20条边,直接先整一颗树,对于多余的边的两个端点,每个跑一遍Dijkstra。
查询的时候直接取最小就好了。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>

using namespace std;

typedef long long ll;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll MAXN = 1e5+10;

struct edge {
    ll nt, to, v;
} E[MAXN << 1];

struct heap {
    ll dis, v;
    friend bool operator < (heap a, heap b) {
		return a.dis > b.dis;
	}
};

bool vis[MAXN], used[MAXN << 1];
ll N, M, head[MAXN], dep[MAXN], cnt = -1, Q, fa[22][MAXN], dis[22][MAXN], di[44][MAXN];
vector <ll> q;

void add(ll, ll, ll);
void dfs(ll);
void dik(ll, ll);
ll lca(ll, ll);

int main() {
    memset(head, -1, sizeof(head));
    scanf("%lld%lld", &N, &M);
    for (ll i = 1, x, y, v; i <= M; i++) {
        scanf("%lld%lld%lld", &x, &y, &v);
        add(x, y, v);
        add(y, x, v);
    }
    dfs(1);
    for (ll i = 1; i <= M * 2; i++) {
        if (!used[i]) {
            used[i] = used[i ^ 1] = 1;
            q.push_back(E[i].to);
            q.push_back(E[i ^ 1].to);
        }
    }
    sort(q.begin(), q.end());
    q.erase(unique(q.begin(), q.end()), q.end());
    for (ll i = 0; i < (ll)q.size(); i++) {
        dik(q.at(i), i+1);
    }
    scanf("%lld", &Q);
    for (ll i = 1, a, b; i <= Q; i++) {
        scanf("%lld%lld", &a, &b);
        //dst...
        ll san = lca(a, b);
        for (ll i = 0; i < (ll)q.size(); i++) {
            san = min(san, di[i+1][a] + di[i+1][b]);
        }
        printf("%lld\n", san);
    }
    return 0;
}

ll lca(ll x, ll y) {
    ll ret = 0;
    if (dep[x] < dep[y]) {
        swap(x, y);
    }
    ll hi = dep[x] - dep[y];
    for (ll i = 20; ~i; i--) {
        if ((hi >> i) & 1) {
            ret += dis[i][x];
            x = fa[i][x];
        }
    }
    if (x == y) return ret;
    for (ll i = 20; ~i; i--) {
        if (fa[i][x] != fa[i][y]) {
            ret += dis[i][x];
            ret += dis[i][y];
            x = fa[i][x];
            y = fa[i][y];
        }
    }
    return ret + dis[0][x] + dis[0][y];
}

void dik(ll st, ll id) {
    priority_queue <heap> now;
    now.push({0, st});
    for (ll i = 1; i <= N; i++) vis[i] = 0, di[id][i] = INF;
    di[id][st] = 0;
    while (!now.empty()) {
        heap nt = now.top(); now.pop();
        if (vis[nt.v]) continue;
        for (ll i = head[nt.v]; ~i; i = E[i].nt) {
            ll v = E[i].to;
            if (di[id][v] > di[id][nt.v] + E[i].v) {
                di[id][v] = di[id][nt.v] + E[i].v;
                now.push({di[id][v], v});
            }
        }
    }
}

void dfs(ll n) {
    vis[n] = 1;
    for (ll i = 1; i <= 20; i++) {
        fa[i][n] = fa[i-1][fa[i-1][n]];
        dis[i][n] = dis[i-1][fa[i-1][n]] + dis[i-1][n];
    }
    for (ll i = head[n]; ~i; i = E[i].nt) {
        ll v = E[i].to;
        if (vis[v]) continue;
        used[i] = used[i ^ 1] = 1;
        fa[0][v] = n;
        dis[0][v] = E[i].v;
        dep[v] = dep[n] + 1;
        dfs(v);
    }
}

void add(ll x, ll y, ll v) {
    cnt++;
    E[cnt].to = y;
    E[cnt].nt = head[x];
    head[x] = cnt;
    E[cnt].v = v;
}

posted @ 2020-09-18 14:46  Gensokyo_Alice  阅读(95)  评论(0)    收藏  举报