【树链剖分】【最大生成树】[NOIP2013]codevs3287 货车运输

题目点这里


嗯……我知道正解是LCA倍增……但是补这个题的时候第一反应就是树剖,于是我就愉快地写树剖了……

用树剖的话复杂度会多一个log不过常数写的小点话几乎可以忽略不计。代码量比正解大那么1000b的样子……毕竟有个线段树还有两个dfs

先用kruskal建个最大生成森林出来,然后把每棵树剖分一下就行了。线段树可以用一个,因为互相不影响


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

using namespace std;

int N, M, Q;
struct e {
    int u, v, w;
    bool operator < (const e &b) const {
        return w > b.w;
    }
}edge[50005];
queue <e> q;
int f[10005];
int find(int x) { return (x == f[x]) ? x : f[x] = find(f[x]); }

struct ed {
    int v, w, next;
}e[100005];
int head[10005], k = 1;

inline void adde(int u, int v, int w)
{
    e[k] = (ed) { v, w, head[u] }; head[u] = k ++;
    e[k] = (ed) { u, w, head[v] }; head[v] = k ++;
}

int vis[10005], belong[10005], rcnt, root[10005];
int fa[10005], son[10005], size[10005], dep[10005];
int top[10005], w[10005], tot;

void dfs(int u)
{
    size[u] = 1; son[u] = 0;
    for (int i = head[u]; i; i = e[i].next) {
        int v = e[i].v; if (v == fa[u]) continue;
        fa[v] = u; dep[v] = dep[u] + 1;
        vis[v] = 1; belong[v] = rcnt;
        dfs(v); size[u] += size[v];
        if (size[v] > size[son[u]]) son[u] = v;
    }
}

void build_tree(int u, int tp)
{
    w[u] = ++ tot; top[u] = tp;
    if (son[u]) build_tree(son[u], tp);
    for (int i = head[u]; i; i = e[i].next) {
        int v = e[i].v; if (v == fa[u] || v == son[u]) continue;
        build_tree(v, v);
    }
}

#define lc (u << 1)
#define rc (u << 1 | 1)

namespace BIT {
    int mmin[10005 << 2];
    
    inline void init() { memset(mmin, 0x3f, sizeof(mmin)); }
    
    void update(int u, int l, int r, const int &pos, const int &c)
    {
        if (l == r) { mmin[u] = c; return; }
        int mid = (l + r) >> 1;
        if (pos <= mid) update(lc, l, mid, pos, c);
        else update(rc, mid + 1, r, pos, c);
        mmin[u] = min(mmin[lc], mmin[rc]);
    }
    
    int Min(int u, int l, int r, int L, int R)
    {
        if (l == L && r == R) return mmin[u];
        int mid = (l + r) >> 1;
        if (R <= mid) return Min(lc, l, mid, L, R);
        if (L > mid) return Min(rc, mid + 1, r, L, R);
        return min(Min(lc, l, mid, L, mid), Min(rc, mid + 1, r, mid + 1, R));
    }
}

int Query(int u, int v)
{
    int f1 = top[u], f2 = top[v], res = 0x3f3f3f3f;
    while (f1 ^ f2) {
        if (dep[f1] > dep[f2]) { swap(f1, f2); swap(u, v); }
        res = min(res, BIT :: Min(1, 1, tot, w[f2], w[v]));
        v = fa[f2]; f2 = top[v];
    }
    if (u == v) return res;
    if (dep[u] > dep[v]) swap(u, v);
    return min(res, BIT :: Min(1, 1, tot, w[son[u]], w[v]));
}

int main()
{
    cin >> N >> M;
    for (int i = 1; i <= M; ++ i) scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
    sort(edge + 1, edge + M + 1);
    for (int i = 1; i <= N; ++ i) f[i] = i;
    for (int i = 1; i <= M; ++ i) {
        int u = edge[i].u, v = edge[i].v;
        if (find(u) == find(v)) continue;
        f[f[u]] = f[v]; adde(u, v, edge[i].w);
        q.push(edge[i]);
    }
    
    for (int i = 1; i <= N; ++ i) if (!vis[i]) {
        vis[i] = 1; belong[i] = ++rcnt; root[rcnt] = i; dfs(i);
    }
    for (int i = 1; i <= rcnt; ++ i) build_tree(root[i], root[i]);
    BIT :: init();
    while (q.size()) {
        struct e temp = q.front(); q.pop();
        int u = temp.u, v = temp.v; if (dep[v] > dep[u]) swap(u, v);
        BIT :: update(1, 1, tot, w[u], temp.w);
    }
    
    for (cin >> Q; Q --; ) {
        int x, y; scanf("%d%d", &x, &y);
        if (belong[x] ^ belong[y]) puts("-1");
        else printf("%d\n", Query(x, y));
    }
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值