uva 12655 Trucks [LCA](树链剖分+MST)

The Subtle Balloons Company (SBC) is the main balloon provider for programming contests; it has
huge factories and warehouses, as well as an extensive truck
eet to ensure the contestants' happiness.
There are lots of competition sites in Nlogonia, and all of them hired SBC for supplying balloons for
their contests. Nlogonia is an archipelago connected by several bridges. Every island of Nlogonia may
have several regional sites and may also house several SBC warehouses.
When planning the routes for balloon deliveries, SBC faced a problem: for safety issues, every
bridge in Nlogonia has some maximum weight limit for vehicles which cross it. And because of the
great net weight of the transported merchandise, SBC operations' chief asked you to write a program to
determine the maximum weight allowed to be transported between warehouses and competition sites.
Input
The input contains several test cases. The rst line of a test case contains three integers N, M and S
which indicate, respectively, the number of islands, the number of bridges that connect the islands and
the number of sites. The islands are numbered from 1 to N.
Each of the next M lines describes a bridge. The description of a bridge consists in a line with
three integers A, B and W, indicating respectively the two islands connected by the bridge and the
maximum weight allowed in that bridge, in tons.
All bridges are two-way roads; every pair of islands is connected by at most one bridge; and it is
possible to reach every other island in the archipelago using only bridges (naturally it may be needed
to pass through other islands to do so).
Each of the next S lines describe a competition site and contains two integers L and H indicat-
ing, respectively, the number of the island where this site is and the number of the island where the
wharehouse which will be used to deliver the balloons to the site is.
Output
For each site in a test case, in the order they were given, your program must produce a single line,
containing a single integer, the biggest weight which can be transported by truck from the warehouse
to the site.
Restrictions

• 2 ≤ N ≤ 2 × 104
• 1 ≤ M ≤ 105
• 1 ≤ S ≤ 5 × 104
• 1 ≤ A, B, L, H ≤ N, A ̸= B, L ̸= H
• 0 ≤ W ≤ 105


Sample Input
4 5 4
1 2 9
1 3 0
2 3 8
2 4 7
3 4 4
1 4
2 1
3 1
4 3
4 5 2
1 2 30
2 3 20
3 4 10
4 1 40
2 4 50
1 3
1 2


Sample Output
7
9
8
7
20
40

 

1: 如果(u,v)为轻边,则size(v)<=size(u)/2;

2: 从根到某一点的路径上轻边的个数不大于O(logN)

时间复杂度O(N*logN*logN)

 

树链剖分:

view code#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef long long ll;
const int INF = 1<<30;
const int M = 200010;
const int N = 20010;
int n, m, Q;
int pre[N], sz[N], fa[N], top[N], id[N], fid[N];
int dep[N], gid, son[N];
int Min[N<<2];

struct edge
{
    int u, v, w, next;
    bool operator < (const edge &o)const{
        return w>o.w;
    }
    edge(int u, int v, int w):u(u),v(v),w(w) {}
    edge() {}
    edge(int u, int v, int w, int next):u(u),v(v),w(w),next(next) {}
}e[M], mst[M];
int mcnt;

void addedge(int u, int v, int w)
{
    mst[mcnt] = edge(u, v, w, pre[u]);
    pre[u] = mcnt++;
    mst[mcnt] = edge(v, u, w, pre[v]);
    pre[v] = mcnt++;
}

int find(int x)
{
    return x==fa[x]?x:(fa[x]=find(fa[x]));
}

void MST()
{
    mcnt = 0;
    for(int i=0; i<=n; i++) fa[i] = i;
    memset(pre, -1, sizeof(pre));
    sort(e, e+m);
    for(int i=0; i<m; i++)
    {
        int u = find(e[i].u), v = find(e[i].v);
        if(u==v) continue;
//        printf("(%d, %d) ->%d\n", e[i].u, e[i].v, e[i].w);
        fa[u] = v;
        addedge(e[i].u, e[i].v, e[i].w);
    }
}

void dfs(int u, int f, int d)
{
    // fa[u]表示u的父亲,dep[u]表示u的深度
    //sz[u]表示u字节点的个数
    //son[u]与u在同重链上的儿子节点  
    fa[u] = f; dep[u] = d; son[u] = 0; sz[u] = 1;
    for(int i=pre[u]; ~i; i=mst[i].next)
    {
        int v = mst[i].v;
        if(v==f) continue;
        dfs(v, u, d+1);
        sz[u] += sz[v];
        if(sz[son[u]] < sz[v]) son[u] = v;
    }
}

void get_pos(int u, int f)
{
    //id[u]表示u与其父亲节点的连边,在线段树中的位置
    id[u] = ++gid;
    fid[gid] = u;//fid与id数组相反,在这道题没什么用
    top[u] = f;//top[u] 表示u所在的重链的顶端节点
    if(son[u]!=0) get_pos(son[u], f);
    for(int i=pre[u]; ~i; i=mst[i].next)
    {
        int v = mst[i].v;
        if(v==fa[u] || v==son[u]) continue;
        get_pos(v, v);
    }
}

void build(int l, int r, int rt)
{
    if(l==r){
        Min[rt] = INF;
        return ;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
}

void update(int p, int c, int l, int r, int rt)
{
    if(l==r){
        Min[rt] = c;
        return ;
    }
    int m = (l+r)>>1;
    if(p<=m) update(p, c, lson);
    else update(p, c, rson);
    Min[rt] = min(Min[rt<<1], Min[rt<<1|1]);
}

int query(int L, int R, int l ,int r, int rt)
{
    if(L<=l && R>=r) return Min[rt];
    int m = (l+r)>>1, ans = INF;
    if(L<=m) ans = min(ans, query(L,R,lson));
    if(R>m) ans = min(ans, query(L,R,rson));
    return ans;
}

int lca(int u, int v)
{
    int fv = top[v], fu = top[u];
    int ans = INF;
    while(fv!=fu)
    {
        if(dep[fv]>dep[fu])
        {
            swap(fv, fu); swap(u,v);
        }
        ans = min(ans, query(id[fu], id[u], 1, gid, 1));
        u = fa[fu];
        fu = top[u];
    }
    if(dep[u]<dep[v]) swap(u, v);
    if(u!=v) ans = min(ans, query(id[v]+1, id[u], 1, gid, 1));//ti[v]指的是v与其父亲的边,所以+1 
    return ans;
}

int main()
{
//    freopen("in.txt", "r", stdin);
    while(scanf("%d%d%d", &n, &m, &Q)>0)
    {
        for(int i=0; i<m; i++)
            scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
        MST();
        sz[1] = 0, gid = 0;
        dfs(1, 1, 1);
        get_pos(1, 1);
        build(1, gid, 1);
        int u, v;
        for(int i=0; i<mcnt; i++)
        {
            int u = mst[i].u, v = mst[i].v;
            if(dep[u]<dep[v]) swap(u,v);
            update(id[u], mst[i].w, 1, gid, 1);
        }
        while(Q--)
        {
            scanf("%d%d", &u, &v);
            printf("%d\n", lca(u,v));
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/zyx1314/p/3911574.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值