LightOJ 1162 Min Max Roads(LCA倍增法或树链剖分)

本文介绍了一种解决MinMaxRoads问题的方法,该问题是寻找两点间路径上的最大和最小边权值。文章提供了两种解决方案:一是使用LCA倍增法进行预处理;二是采用树链剖分方法,并详细阐述了每种方法的实现细节。

Min Max Roads

Time Limit:3000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu

Description

You live in a Big country where there are many bi-directional roads connecting the cities. Since the people of the country are quite intelligent, they designed the country such that there is exactly one path to go from one city to another. A path consists of one or more connected roads.

Here cities are denoted by integers and each road has a cost of traveling. Now you are given the information about the Country. And you are given some queries, each consists of two cities. You have to find the shortest and longest road in the path from one city to another.

Input

Input starts with an integer T(5) , denoting the number of test cases.

The first line of each case is a blank line. The next line contains n(2n105) denoting the number of cities. Then there will be n1 lines containing three integers each. They will be given in the form u,v,w(1u,vn,0<w105,uv) meaning that there is a road between u and v and the cost of the road is w .

The next line contains an integer q(1q25000) denoting the number of queries. Each of the next q lines contains two integers x and y(1x,yn,xy) .

Output

For each case, print the case number in a single line. Then for each query x y, you should print one line containing the shortest and longest road along the path. See the samples for formatting.

Sample Input

2

6
3 6 50
2 5 30
2 4 300
1 2 100
1 3 200
4
1 4
4 6
2 5
3 5

2
1 2 100
1
1 2

Sample Output

Case 1:
100 300
50 300
30 30
30 200
Case 2:
100 100

Hint

Dataset is huge. Use faster i/o methods.

Problem Setter: Jane Alam Jan
Developed and Maintained by
JANE ALAM JAN
Copyright © 2012
LightOJ, Jane Alam Jan

题意

给你一棵顶点数为 n 的树,然后有 q 个询问,询问 u v 之间的路径上边权的最大值和最小值

解题思路

可以用LCA倍增法, O(nlogn) 进行预处理,然后是 O(logn) 查询 u v 的最大值和最小值
也可以用树链剖分,非常明显,裸题

代码

/*除去冗长的头文件*/
const double PI = 3.1415926535898;
const double eps = 1e-10;
const int MAXM = 1e5 + 5;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;


struct Edge {
    int u, v, cost, nxt;
} E[MAXN << 1];

int Head[MAXN], tot;
int deep[MAXN];
int p[MAXN][20];
int Mi[MAXN][20];
int Ma[MAXN][20];

void edge_init() {
    tot = 0;
    mem(Head, -1);
    mem(p, -1);
    mem(Ma, 0);
    mem(Mi, 0x3f);
}

void add_edge(int u, int v, int cost) {
    E[tot].u = u;
    E[tot].v = v;
    E[tot].cost = cost;
    E[tot].nxt = Head[u];
    Head[u] = tot ++;
}

void dfs(int u, int pre, int d) {
    deep[u] = d;
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == pre) continue;
        dfs(v, u, d + 1);
        p[v][0] = u;
        Mi[v][0] = E[i].cost;
        Ma[v][0] = E[i].cost;
    }
}

void b_init(int max_n) {
    for(int j = 1; 1 << j <= max_n; j ++) {
        for(int i = 1; i <= max_n; i ++) {
            if(p[i][j - 1] != -1) {
                p[i][j] = p[p[i][j - 1]][j - 1];
                Mi[i][j] = min(Mi[i][j - 1], Mi[p[i][j - 1]][j - 1]);
                Ma[i][j] = max(Ma[i][j - 1], Ma[p[i][j - 1]][j - 1]);
            }
        }
    }
}

PII LCA(int a, int b) {
    int Max = 0, Min = INF;
    if(deep[a] < deep[b]) swap(a, b);
    int dcp = 0;
    for(; 1 << dcp <= deep[a]; dcp ++);
    dcp --;

    for(int j = dcp; j >= 0; j --) {
        if(deep[a] - (1 << j) >= deep[b]) {
            Max = max(Max, Ma[a][j]);
            Min = min(Min, Mi[a][j]);
            a = p[a][j];
        }
    }

    if(a == b) return make_pair(Min, Max);

    for(int j = dcp; j >= 0; j --) {
        if(p[a][j] != -1 && p[a][j] != p[b][j]) {
            Max = max(Max, Ma[a][j]);
            Min = min(Min, Mi[a][j]);
            Max = max(Max, Ma[b][j]);
            Min = min(Min, Mi[b][j]);
            a = p[a][j];
            b = p[b][j];
        }
    }
    Max = max(Max, Ma[a][0]);
    Min = min(Min, Mi[a][0]);
    Max = max(Max, Ma[b][0]);
    Min = min(Min, Mi[b][0]);
    return make_pair(Min, Max);
}

int T, n;


int main() {
#ifndef ONLINE_JUDGE
    FIN;
    //FOUT;
#endif
    IO_Init();
    int cas = 1;
    scanf("%d", &T);
    while(T --) {
        int u, v, cost;
        edge_init();
        scanf("%d", &n);
        for(int i = 0; i < n - 1; i ++) {
            scanf("%d%d%d", &u, &v, &cost);
            add_edge(u, v, cost);
            add_edge(v, u, cost);
        }
        dfs(1, 0, 0);
        b_init(n);
        int q, a, b;
        printf("Case %d:\n", cas ++);
        scanf("%d", &q);
        while(q --) {
            scanf("%d%d", &a, &b);
            PII p = LCA(a, b);
            printf("%d %d\n", p.first, p.second);
        }
    }

    return 0;
}

树链剖分

/*除去冗长的头文件*/

const double PI = 3.1415926535898;
const double eps = 1e-10;
const int MAXM = 1e5 + 5;
const int MAXN = 1e5 + 5;
const int INF = 0x3f3f3f3f;



struct Edge {
    int u, v, nxt, cost;
} E[MAXN << 1], TmpE[MAXN << 1];

int Head[MAXN], tot, sz;
int deep[MAXN << 1], fa[MAXN << 1], ve[MAXN << 1], top[MAXN << 1], p[MAXN << 1], fp[MAXN << 1],  son[MAXN << 1];

void edge_init() {
    tot = 0;
    sz = 0;
    mem(Head, -1);
}

void add_edge(int u, int v, int cost) {
    E[tot].u = u;
    E[tot].v = v;
    E[tot].cost = cost;
    E[tot].nxt = Head[u];
    Head[u] = tot ++;
}

void dfs1(int u, int pre, int d) {
    deep[u] = d;
    fa[u] = pre;
    ve[u] = 1;
    son[u] = -1;
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == pre) continue;
        dfs1(v, u, d + 1);
        ve[u] += ve[v];
        if(son[u] == -1 || ve[v] > ve[son[u]]) {
            son[u] = v;
        }
    }
}

void dfs2(int u, int sp) {
    top[u] = sp;
    p[u] = ++ sz;
    fp[p[u]] = u;
    if(son[u] == -1) return;
    dfs2(son[u], sp);
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(v == son[u] || v == fa[u]) continue;
        dfs2(v, v);
    }
}

int sum[2][MAXN << 2];

void push_up(int rt) {
    sum[0][rt] = min(sum[0][rt << 1], sum[0][rt << 1 | 1]);
    sum[1][rt] = max(sum[1][rt << 1], sum[1][rt << 1 | 1]);
}

void build(int rt, int l, int r) {
    sum[1][rt] = 0;
    sum[0][rt] = INF;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    push_up(rt);
}

void update(int p, int val, int rt, int l, int r) {
    if(l == r) {
        sum[0][rt] = sum[1][rt] = val;
        return ;
    }
    int mid = (l + r) >> 1;
    if(p <= mid) {
        update(p, val, lson);
    } else {
        update(p, val, rson);
    }
    push_up(rt);
}

int query(int L, int R, int rt, int l, int r, int flag) {
    if(L <= l && r <= R) {
        return sum[flag][rt];
    }
    int mid = (l + r) >> 1;
    int ret = flag ?  0 : INF;
    if(L <= mid) {
        ret =  flag ? max(ret, query(L, R, lson, flag)) : min(ret, query(L, R, lson, flag));
    }
    if(mid < R) {
        ret =  flag ? max(ret, query(L, R, rson, flag)) : min(ret, query(L, R, rson, flag));
    }
    return ret;
}

int find(int u, int v, int flag) {
    int f1 = top[u], f2 = top[v];
    int tmp = flag ? 0 : INF;
    while(f1 != f2) {
        if(deep[f1] < deep[f2]) {
            swap(f1, f2);
            swap(u, v);
        }
        tmp = flag ? max(tmp, query(p[f1], p[u], 1, 1, sz, flag)) : min(tmp, query(p[f1], p[u], 1, 1, sz, flag));
        u = fa[f1];
        f1 = top[u];
    }
    if(v == u) return tmp;
    if(deep[u] > deep[v]) swap(u, v);
    return flag ? max(tmp, query(p[son[u]], p[v], 1, 1, sz, flag)) : min(tmp, query(p[son[u]], p[v], 1, 1, sz, flag));
}

int T, n;

int main() {
#ifndef ONLINE_JUDGE
    //FIN;
    //FOUT;
#endif
    IO_Init();
    int cas = 1;
    scanf("%d", &T);
    while(T --) {
        edge_init();
        scanf("%d", &n);
        for(int i = 0; i < n - 1; i ++) {
            scanf("%d%d%d", &TmpE[i].u, &TmpE[i].v, &TmpE[i].cost);
            add_edge(TmpE[i].u, TmpE[i].v, TmpE[i].cost);
            add_edge(TmpE[i].v, TmpE[i].u, TmpE[i].cost);
        }
        dfs1(1, 0, 0);
        dfs2(1, 1);
        build(1, 1, sz);

        for(int i = 0; i < n - 1; i ++) {
            if(deep[TmpE[i].u] > deep[TmpE[i].v]) swap(TmpE[i].u, TmpE[i].v);
            update(p[TmpE[i].v], TmpE[i].cost, 1, 1, sz);
        }
        printf("Case %d:\n", cas ++);
        int q, a, b;
        scanf("%d", &q);
        while(q --) {
            scanf("%d%d", &a, &b);
            printf("%d %d\n", find(a, b, 0), find(a, b, 1));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值