LightOJ 1162 Min Max Roads(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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值