zoukankan      html  css  js  c++  java
  • [BZOJ3732]Network

    [BZOJ3732]Network

    试题描述

    给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。 
    图中有M条边 (1 <= M <= 30,000) ,第j条边的长度为: d_j ( 1 < = d_j < = 1,000,000,000).

    现在有 K个询问 (1 < = K < = 15,000)。 
    每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?

    输入

    第一行: 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点的所有路径中,最长的边最小值是多少?

    输出

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

    输入示例

    6 6 8
    1 2 5
    2 3 4
    3 4 3
    1 4 8
    2 5 7
    4 6 2
    1 2
    1 3
    1 4
    2 3
    2 4
    5 1
    6 2
    6 1

    输出示例

    5
    5
    5
    4
    4
    7
    4
    5

    数据规模及约定

    1 <= N <= 15,000
    1 <= M <= 30,000
    1 <= d_j <= 1,000,000,000
    1 <= K <= 15,000

    题解

    一开始我自己yy了一个做法。考虑只有一个询问,那么显然是二分+并查集,然后我就想了一个能够“批处理”多组询问的方法(离线),就是对于答案区间 [al, ar],满足这个答案区间的操作区间为 [ql, qr],那么我们可以像二分那样搞一个 mid = (al + ar) / 2,然后对于 [ql, qr] 区间内的所有询问check一下,像归并排序那样把能够满足答案 mid 的询问放到左边,它们属于新的答案区间 [al, mid],不满足 mid 的询问放到右边,它们属于答案区间 [mid + 1, ar],然后递归处理就好了,边界是当 al = ar 时,所有在这个答案区间中的询问的答案显然都是 al (或 ar),当 ql > qr(即询问集合为空时)直接 return。后来发现这就是传说中的整体二分,看到自己能凭空yy出一个整体二分的方法感到很高兴,然而交上去便T了。。。搞下数据本地开 O2 测是快的飞起啊。。。。。

    没办法上网搜一下题解,发现这TM不是 NOIP 题吗?!求一遍最小生成树再搞一个倍增 LCA 就好了。。。。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
     
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
        if(Head == Tail) {
            int l = fread(buffer, 1, BufferSize, stdin);
            Tail = (Head = buffer) + l;
        }
        return *Head++;
    }
    int read() {
        int x = 0, f = 1; char c = Getchar();
        while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
        while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
        return x * f;
    }
     
    #define maxn 15010
    #define maxm 30010
    #define maxq 20010
    #define maxlog 15
    int n, m, q;
    struct Edge {
        int a, b, c;
        bool operator < (const Edge& t) const { return c < t.c; }
    } es[maxm];
     
    int pa[maxn];
    int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }
     
    int ToT, head[maxn], next[maxm], to[maxm], dist[maxm];
    void AddEdge(int a, int b, int c) {
        to[++ToT] = b; dist[ToT] = c; next[ToT] = head[a]; head[a] = ToT;
        swap(a, b);
        to[++ToT] = b; dist[ToT] = c; next[ToT] = head[a]; head[a] = ToT;
        return ;
    }
     
    int dep[maxn], fa[maxn][maxlog], mxd[maxn][maxlog];
    void build(int u) {
        for(int i = 1; i < maxlog; i++) {
            int a = fa[u][i-1];
            fa[u][i] = fa[a][i-1];
            mxd[u][i] = max(mxd[u][i-1], mxd[a][i-1]);
        }
        for(int e = head[u]; e; e = next[e]) if(to[e] != fa[u][0]) {
            fa[to[e]][0] = u; mxd[to[e]][0] = dist[e];
            dep[to[e]] = dep[u] + 1;
            build(to[e]);
        }
        return ;
    }
    int query(int a, int b) {
        if(dep[a] < dep[b]) swap(a, b);
        int ans = 0;
        for(int i = maxlog - 1; i >= 0; i--) if(dep[a] - (1 << i) >= dep[b])
            ans = max(ans, mxd[a][i]), a = fa[a][i];
        if(a == b) return ans;
        for(int i = maxlog - 1; i >= 0; i--) if(fa[a][i] != fa[b][i])
            ans = max(ans, max(mxd[a][i], mxd[b][i])), a = fa[a][i], b = fa[b][i];
        return max(ans, max(mxd[a][0], mxd[b][0]));
    }
     
    int main() {
        n = read(); m = read(); q = read();
        for(int i = 1; i <= m; i++) es[i].a = read(), es[i].b = read(), es[i].c = read();
         
        sort(es + 1, es + m + 1);
        for(int i = 1; i <= n; i++) pa[i] = i;
        for(int i = 1; i <= m; i++) {
            int u = findset(es[i].a), v = findset(es[i].b);
            if(u != v) {
                pa[v] = u;
                AddEdge(es[i].a, es[i].b, es[i].c);
            }
        }
        build(1);
        while(q--) {
            int a = read(), b = read();
            printf("%d
    ", query(a, b));
        }
         
        return 0;
    }
    
  • 相关阅读:
    第一次设计作业
    项目选题报告(团队)
    第二次结队作业
    团队第一次作业
    原型设计(结对第一次)
    第二次作业——个人项目实战
    对于软件工程专业的思考
    电场与磁场
    透明层上的层或数字不透明
    Visiual Studio2012 CLR20r3问题
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5755641.html
Copyright © 2011-2022 走看看