[luogu P1967] 货车运输

题目链接:

货车运输

题目分析:

kruscal+树剖板套板

首先在一个连通块里的两个点之间的路径上边权最小值的最大值(有点绕)一定在最大生成树上,因为最大生成树使新图连通且边权最大
然后在最大生成树上树剖/倍增求两点路径中的最小值即可,注意边权下放到点后查询时要跳过\(LCA\)
图可能不连通(\(\#21\)即是不连通的情况),此时需要对每棵\(BST\)的根\(dfs\)一遍

代码:

#include<bits/stdc++.h>
#define N (100000 + 10)
#define int long long
using namespace std;
inline int read() {
    int cnt = 0, f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -f; c = getchar();}
    while (isdigit(c)) {cnt = (cnt << 3) + (cnt << 1) + c - '0'; c = getchar();}
    return cnt * f;
}
const int INF = (1 << 30);
int n, m;
int fa[N], father[N], tot, w[N], a[N], num[N], id[N], idx, top[N], dep[N], siz[N], son[N];
int nxt[N], first[N], to[N];
int x, y, z, q;
struct node {
    int u, v, dat;
}edge[N];
bool cmp (node x, node y) {
    return x.dat > y.dat;
}
void add(int x, int y, int z) {nxt[++tot] = first[x], first[x] = tot, to[tot] = y, w[tot] = z;}
int get_father(int x) {return fa[x] == x ? x : fa[x] = get_father(fa[x]);}
void dfs_(int x, int Fa) {
    father[x] = Fa, dep[x] = dep[Fa] + 1, siz[x] = 1;
    for (register int i = first[x]; i; i = nxt[i]) {
        int v = to[i];
        if (v == Fa) continue;
        a[v] = w[i];
        dfs_(v, x);
        siz[x] += siz[v];
        if (siz[son[x]] < siz[v]) son[x] = v;
    }
}
void dfs__(int x, int tp) {
    top[x] = tp, num[x] = ++idx, id[idx] = x;
    if (son[x]) dfs__(son[x], tp);
    for (register int i = first[x]; i; i = nxt[i]) {
        int v = to[i];
        if (num[v]) continue;
        dfs__(v, v);
    }
}
struct node2 {
    int l, r, dat;
    #define l(p) tree[p].l
    #define r(p) tree[p].r
    #define dat(p) tree[p].dat 
}tree[N << 2];
void pushup(int p) {
    dat(p) = min(dat(p << 1), dat(p << 1 | 1));
}
void build (int p, int l, int r) {
    l(p) = l, r(p) = r;
    if (l == r) {dat(p) = a[id[l]]; return;}
    int mid = (l + r) >> 1;
    build (p << 1, l, mid);
    build (p << 1 | 1, mid + 1, r);
    pushup(p);
}
long long query (int p, int l, int r) {
	if (l <= l(p) && r >= r(p)) return dat(p);
	long long ans = INF;
	int mid = (l(p) + r(p)) >> 1;
	if (l <= mid) ans = min(ans, query(p << 1, l, r));
	if (r > mid) ans = min(ans, query(p << 1 | 1, l, r));
	return ans;
}
long long Query(int u, int v) {
	long long ans = INF;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
		ans = min(ans, query(1, num[top[u]], num[u]));
		u = father[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
	ans = min(ans, query(1, num[v] + 1, num[u]));
	return ans; 
}
signed main() {
    n = read(), m = read();
    for (register int i = 1; i <= n; ++i) fa[i] = i;
    for (register int i = 1; i <= m; ++i) {
        edge[i].u = read(), edge[i].v = read(), edge[i].dat = read();
    }
    sort (edge + 1, edge + m + 1, cmp);
    for (register int i = 1; i <= m; i++) {
    	if (tot / 2 == n - 1) break;
        int fx = get_father(edge[i].u), fy = get_father(edge[i].v);
        if (fx == fy) continue;
        fa[fy] = fx, add(edge[i].u, edge[i].v, edge[i].dat), add(edge[i].v, edge[i].u, edge[i].dat);
    }
    for (register int i = 1; i <= n; ++i) if (fa[i] == i) dfs_(i, 0), dfs__(i, i);
    build(1, 1, n);
    q = read();
    for (register int i = 1; i <= q; ++i) {
        x = read(), y = read();
        if (get_father(x) != get_father(y)) {printf("-1\n"); continue;}
		printf("%lld\n", Query(x, y));
    }
    return 0;
}
posted @ 2019-09-18 09:15  kma_093  阅读(129)  评论(0编辑  收藏  举报