B. 【普转提七联测 Day 6】载重

题目大意

B 国有 \(n\) 个城市, 一些城市间有若干条双向道路相连

每条道路有一个限制重量,大于该限制重量的车都不能通过

现在运输公司有 \(q\) 辆货车,每辆货车想从 \(s_i\) 市到 \(t_i\) 市,车的重量是 \(w_i\)

请问每一辆车是否能够到达目的地

Solution

Std

并查集在加边的时候从大到小加,并处理相关询问;

由于从大到小加,可以保证当前是最优的方案,直接处理。

实质也就是MST上的路径最值,不过离线下来,通过一个过程去实现,代码少。

My Solution

首先很明显求的是路径最小值最大。

而显而易见,最大生成树可以保证树上最小值尽可能大。

问题转换成求树上路径最小。

最大生成树 + 路径最小值(树链剖分 + ST表)实现,或树上倍增。

\(\mathrm{Code:}\)

#include <algorithm>
#include <climits>
#include <cstdio>
#include <iostream>
#define rint register int
#define FOR(i, a, b) for (rint i = (a); i <= (b); ++i)
#define S_H(T, i, u) for (rint i = T.fl[u]; i; i = T.net[i])
#define swap(x, y) (x ^= y ^= x ^= y)
const int N = 1e5 + 10, M = 3e5 + 10;
int n, m, Q;
int si[N], hs[N], f[N], d[N], a[N];
int top[N], tr[N], vs = 0, pr[N];
class Edge {
   public:
    int x, y, z;
} e[M << 1];
struct Tree {
    int to[N << 1], net[N << 1], w[N << 1];
    int fl[N], len, in[N];
    inline void inc(int x, int y, int z) {
        to[++len] = y;
        w[len]    = z;
        ++in[y];
        net[len] = fl[x];
        fl[x]    = len;
    }
} T;
struct US_find {
    int f[N], n;
    inline void Build(int _) {
        n = _;
        FOR(i, 1, n)
        f[i] = i;
    }
    inline void Modify(int x, int y, int z) {
        int u = Get(x), v = Get(y);
        if (u != v) {
            f[u] = v;
            T.inc(x, y, z);
            T.inc(y, x, z);
        }
    }
    inline int Get(int x) { return x == f[x] ? x : f[x] = Get(f[x]); }
};
struct ST {
#define I(k) (1 << k)
    int f[N][30], lg[N];
    inline int Ask(int l, int r) {
        int t = lg[r - l + 1];
        return std ::min(f[l][t], f[r - I(t) + 1][t]);
    }
    inline void Work() {
        lg[0] = -1;
        FOR(i, 1, n)
        lg[i] = lg[i >> 1] + 1;
        FOR(i, 1, n)
        f[i][0] = pr[i];
        FOR(j, 1, 20)
        FOR(i, 1, n - I(j) + 1)
        f[i][j] = std ::min(f[i][j - 1], f[i + I(j - 1)][j - 1]);
    }
} S;
											//定义部分
inline int read() {
    int s = 0, w = 1;
    char c = getchar();
    while ((c < '0' || c > '9') && c != '-') c = getchar();
    if (c == '-') w = -1, c = getchar();
    while (c <= '9' && c >= '0')
        s = (s << 1) + (s << 3) + c - '0', c = getchar();
    return s * w;
}
template <class T>
inline void write(T x) {
    if (x < 0) x = ~x + 1, putchar('-');
    if (x > 9) write(x / 10);
    putchar(x % 10 + 48);
    return void();
}

void dfs(int u, int fa) {
    si[u] = 1;
    S_H(T, i, u) {
        int v = T.to[i];
        if (v == fa) continue;
        f[v] = u, d[v] = d[u] + 1, a[v] = T.w[i];
        dfs(v, u);
        si[u] += si[v];
        hs[u] = si[hs[u]] < si[v] ? v : hs[u];
    }
}
void dfs_chain(int u, int k) {
    top[pr[tr[u] = ++vs] = u] = k, pr[vs] = a[u];
    if (!hs[u]) return void();
    dfs_chain(hs[u], k);
    S_H(T, i, u) {
        int v = T.to[i];
        if (v == f[u] || v == hs[u]) continue;
        dfs_chain(v, v);
    }
}
inline int Ask_chain(int x, int y) {
    int minn = INT_MAX;
    while (top[x] ^ top[y]) {
        if (d[top[x]] < d[top[y]]) swap(x, y);
        minn = std ::min(minn, S.Ask(tr[top[x]], tr[x]));
        x    = f[top[x]];
    }
    if (x == y) return minn;
    if (d[x] < d[y]) swap(x, y);
    minn = std ::min(minn, S.Ask(tr[y] + 1, tr[x]));
    return minn;
}
 											//树链剖分操作
inline bool cmp(Edge x, Edge y) { return x.z > y.z; }
signed main(void) {
    n = read(), m = read(), Q = read();
    FOR(i, 1, m) {
        int x = read(), y = read(), z = read();
        e[i] = (Edge){x, y, z};
    }
    US_find F;
    F.Build(n);
    std ::sort(e + 1, e + m + 1, cmp);
    FOR(i, 1, m) F.Modify(e[i].x, e[i].y, e[i].z);
    //MST最大生成树
    FOR(i, 1, n)
    if (!si[i]) dfs(i, 0), dfs_chain(i, i);
    //树剖预处理
    S.Work();
    FOR(i, 1, Q) {
        int x = read(), y = read(), z = read();
        if (F.Get(x) != F.Get(y)) {
            puts("No");
            continue;
        }
        //特判是否连通 !important;
        int t = Ask_chain(x, y);
        t >= z ? puts("Yes") : puts("No");
    }
    return 0;
}
posted @ 2020-07-01 18:40  云烟万象但过眼  阅读(53)  评论(0编辑  收藏  举报