jzoj1738. Heatwave

24 篇文章 0 订阅
20 篇文章 0 订阅

Description


  给你N个点的无向连通图,图中有M条边,第j条边的长度为: d_j.
  现在有 K个询问。
  每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Input


  文件名为heatwave.in
  第一行: N, M, K。
  第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
  第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

Output


  对每个询问,输出最长的边最小值是多少。

Data Constraint


50% 1<=N,M<=3000 其中30% K<=5000
​100% 1 <= N <= 15,000   1 <= M <= 30,000   1 <= d_j <= 1,000,000,000   1 <= K <= 20,000

Solution


我好像记得做过类似的题。。

考虑两点的路径上最长边一定都尽可能小,那么这条路径一定是两点之间的最短路。这样我们跑一遍最小生成树去掉不需要的边,再树上倍增维护最长边即可

1A,要是复赛t2这么水就好了

Code


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#define rep(i, st, ed) for (int i = st; i <= ed; i += 1)
#define drp(i, st, ed) for (int i = st; i >= ed; i -= 1)
#define erg(i, st) for (int i = ls[st]; i; i = e[i].next)
#define fill(x, t) memset(x, t, sizeof(x))
#define max(x, y) ((x)>(y)?(x):(y))
#define min(x, y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<(0)?(-(x)):(x))
#define INF 0x3f3f3f3f
#define N 30021
#define E N * 2 + 1
#define L 1001
struct edge {int x, y, w, next;} g[E], e[E];
int len[N][21], acs[N][21], dep[N], fa[N], ls[N];
int edgeCnt = 1;
inline int read() {
    int x = 0, v = 1; char ch = getchar();
    for(; ch<'0'||ch>'9'; v=(ch=='-')?(-1):(v),ch=getchar());
    for(; ch<='9'&&ch>='0'; (x*=10)+=ch-'0',ch=getchar());
    return x * v;
}
inline void addEdge(int x, int y, int w) {
    e[++ edgeCnt] = (edge) {x, y, w, ls[x]}; ls[x] = edgeCnt;
    e[++ edgeCnt] = (edge) {y, x, w, ls[y]}; ls[y] = edgeCnt;
}
inline int getFather(int now) {
    return (!fa[now])?(now):(fa[now] = getFather(fa[now]));
}
inline bool merge(int x, int y) {
    int fx = getFather(x);
    int fy = getFather(y);
    if (fx == fy) {
        return 0;
    }
    fa[fx] = fy;
    return 1;
}
inline bool cmp(edge a, edge b) {
    return a.w < b.w;
}
inline void dfs(int now) {
    rep(i, 1, 20) {
        acs[now][i] = acs[acs[now][i - 1]][i - 1];
        len[now][i] = max(len[now][i - 1], len[acs[now][i - 1]][i - 1]);
    }
    erg(i, now) {
        if (e[i].y == acs[now][0]) {
            continue;
        }
        acs[e[i].y][0] = now;
        len[e[i].y][0] = e[i].w;
        dep[e[i].y] = dep[now] + 1;
        dfs(e[i].y);
    }
}
inline int getLen(int x, int y) {
    int lenX = 0;
    int lenY = 0;
    if (dep[x] < dep[y]) {
        x ^= y;
        y ^= x;
        x ^= y;
    }
    drp(i, 20, 0) {
        if (dep[acs[x][i]] >= dep[y]) {
            lenX = max(lenX, len[x][i]);
            x = acs[x][i];
        }
    }
    if (x == y) {
        return lenX;
    }
    drp(i, 20, 0) {
        if (acs[x][i] != acs[y][i]) {
            lenX = max(lenX, len[x][i]);
            x = acs[x][i];
            lenY = max(lenY, len[y][i]);
            y = acs[y][i];
        }
    }
    lenX = max(lenX, len[x][0]);
    lenY = max(lenY, len[y][0]);
    return max(lenX, lenY);
}
int main(void) {
    int n = read();
    int m = read();
    int k = read();
    rep(i, 1, m) {
        g[i] = (edge) {read(), read(), read()};
    }
    std:: sort(g + 1, g + m + 1, cmp);
    rep(i, 1, m) {
        if (merge(g[i].x, g[i].y)) {
            addEdge(g[i].x, g[i].y, g[i].w);
        }
    }
    dep[1] = 1;
    dfs(1);
    while (k --) {
        int x = read();
        int y = read();
        int prt = getLen(x, y);
        printf("%d\n", prt);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值