zoukankan      html  css  js  c++  java
  • [noip2013]货车运输(kruskal + 树上倍增)

    描述

    A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    格式

    输入格式

    第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。

    接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。

    接下来一行有一个整数 q,表示有 q 辆货车需要运货。

    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

    输出格式

    输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

    样例1

    样例输入1

     
    4 3 
    1 2 4 
    2 3 3 
    3 1 1 
    3
    1 3 
    1 4 
    1 3
    

    样例输出1

     
    3
    -1
    3
    

    限制

    每个测试点1s。

    提示

    对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000; 
    对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000; 
    对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

    因为货车要运输最大货物,必须在整张图的最大生成树上选边,可以想到kruskal算法,但此时若要对每一个询问进行一次遍历的话需要 O(mn) 的时间复杂度,那么就需要把答案预先处理出来。

    RMQ问题的ST算法 是用 d(i, j) 表示 从 i 开始 长度为 2^j 的一段元素之间的最小值

    那么 d(i, j) = min{d(i ,j - 1), d(i + 2 ^ (j - 1), j - 1)}; 从 i 开始长度为 2^j 的最小值 = min{从 i 开始长度为2^(j - 1) 的一段元素的最小值, 从i + 2^(j - 1) + 1开始长度为2^(j - 1)的最小值};

    这个题在处理时同样可以借鉴这种思路,这个题在树上(我也不知道在说啥),所以:

    以 f[i][j] 表示第i个结点的第2^j个祖先是哪个点,那么 f[i][0] 为第i个节点的父亲。

    以 g[i][j] 表示第i个结点到 f[i][j](第i个结点的第2^j个祖先) 的最短距离,那么 g[i][0] 表示第i个节点到自己父亲的(最短)距离。

    转移可以模仿ST算法:

    f[i][j] = f[ f[i][j - 1] ][j - 1]; 第i个点的第2^j个祖先 = 【第i个点第2^(j - 1)的祖先】 的 【第2^(j - 1)的祖先】

    g[i][j] = min(g[i][j - 1], g[ f[i][j - 1] ][j - 1]); 第i个结点到 自己的第2^j个祖先 的最短距离 = min{第i个结点到 自己的第 2^(j - 1) 个祖先 的最短距离,【 第i个结点的第2^(j - 1)个祖先】到 【自己的第2^(j - 1)个祖先】 的最短距离}

    【】只是为了帮助断句。。。

    之后若要查询(x, y)的最短距离只需查询 min{(x, pos)的最短距离,(y, pos)的最短距离} pos为x,y的最近公共祖先

    那么借用dfs的思路即可预处理整张图得到f和g

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <math.h>
      4 #include <algorithm>
      5 using namespace std;
      6 struct node {
      7     int x, y, val;
      8 }edge[50005];
      9 int n, m, cnt;
     10 bool cmp(node a, node b) { return a.val > b.val; }
     11 int u[50005], v[50005], next[50005], first[10005], w[50005];
     12 int in[10005], father[10005], hi[10005];
     13 void addedge(int st, int end, int value)
     14 {
     15     u[++cnt] = st, v[cnt] = end, w[cnt] = value;
     16     next[cnt] = first[st];
     17     first[st] = cnt;
     18 }
     19 int getfather(int x) { return father[x] == x ? x : father[x] = getfather(father[x]); }
     20 void kruskal()
     21 {
     22     int count;
     23     for (int i = 1; i <= n; i++) father[i] = i;
     24     for (int i = 1; i <= m; i++) {
     25         int st = edge[i].x, end = edge[i].y;
     26         int fa = getfather(father[st]), fb = getfather(father[end]);
     27         if (fa != fb) {
     28             addedge(st, end, edge[i].val);
     29             addedge(end, st, edge[i].val);
     30             father[fb] = fa;
     31             count++;
     32             if (count == n - 1) return;
     33         }
     34     }
     35 }
     36 int vis[10005];
     37 int fa[10005][25], Min[10005][25];
     38 void dfs(int o)
     39 {
     40     vis[o] = 1;
     41     for (int i = 1; i <= 16; i++) {
     42         if (hi[o] < (1 << i)) break;
     43         fa[o][i] = fa[fa[o][i - 1]][i - 1];
     44         Min[o][i] = min(Min[o][i - 1], Min[fa[o][i - 1]][i - 1]);
     45     }
     46     for (int i = first[o]; i; i = next[i]) {
     47         int end = v[i];
     48         if (!vis[end]) {
     49             fa[end][0] = o;
     50             Min[end][0] = w[i];
     51             hi[end] = hi[o] + 1;
     52             dfs(end);
     53         }
     54     }
     55 }
     56 int lca(int l, int r)
     57 {
     58     if (hi[l] < hi[r]) swap(l, r);
     59     int t = hi[l] - hi[r];
     60     for (int i = 0; i <= 16; i++) {
     61         if ((1 << i) & t) l = fa[l][i];
     62     }
     63     for (int i = 16; i >= 0; i--) {
     64         if (fa[l][i] != fa[r][i]) {
     65             l = fa[l][i], r = fa[r][i];
     66         }
     67     }
     68     if (l == r) return l;
     69     return fa[l][0];
     70 }
     71 int ask(int l, int r)
     72 {
     73     int ret = 0x3f3f3f3f;
     74     int t = hi[l] - hi[r];
     75     for (int i = 0; i <= 16; i++) {
     76         if (t & (1 << i)) {
     77             ret = min(ret, Min[l][i]);
     78             l = fa[l][i];
     79         }
     80     }
     81     return ret;
     82 }
     83 int main()
     84 {
     85     memset(Min, 0x3f3f3f3f, sizeof(Min));
     86     scanf("%d%d", &n, &m);
     87     for (int i = 1; i <= m; i++) {
     88         scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].val);
     89     }
     90     sort(edge + 1, edge + 1 + m, cmp);
     91     kruskal();
     92     for (int i = 1; i <= n; i++) if (!vis[i]) dfs(i);
     93     int t, l, r;
     94     scanf("%d", &t);
     95     while (t--) {
     96         scanf("%d%d", &l, &r);
     97         if (getfather(father[l]) != getfather(father[r])) printf("-1
    ");
     98         else {
     99             int pos = lca(l, r);
    100             printf("%d
    ", min(ask(l, pos), ask(r, pos)));
    101         }
    102     }
    103     return 0;
    104 }

    变量名不好起啊。

     
  • 相关阅读:
    php无限极分类
    HDU 1176 免费馅饼 (类似数字三角形的题,很经典,值得仔细理解的dp思维)
    HDU 1158(非常好的锻炼DP思维的题目,非常经典)
    HDU 1165 公式推导题
    HDU 1069 Monkey and Banana(转换成LIS,做法很值得学习)
    HDU 1059(多重背包加二进制优化)
    HDU 1058(打表)
    oracle11g之管理oracle数据库笔记(理论基础知识)
    oracle11g之Oracle体系结构(理论基础知识)
    HDU 1025 LIS二分优化
  • 原文地址:https://www.cnblogs.com/y7070/p/4738364.html
Copyright © 2011-2022 走看看