zoukankan      html  css  js  c++  java
  • P1967 货车运输【LCA】【生成树】

    题目描述

    A 国有 nn 座城市,编号从 11 到 nn,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。

    现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    输入格式

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

    接下来 mm 行每行三个整数 x, y, zx,y,z,每两个整数之间用一个空格隔开,表示从 xx 号城市到 yy 号城市有一条限重为 zz 的道路。
    注意: x eq yx=y,两座城市之间可能有多条道路 。

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

    接下来 qq 行,每行两个整数 x,yx,y,之间用一个空格隔开,表示一辆货车需要从 xx 城市运输货物到 yy 城市,保证 x eq yx=y

    输出格式

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

    输入输出样例

    输入 #1
    4 3
    1 2 4
    2 3 3
    3 1 1
    3
    1 3
    1 4
    1 3
    输出 #1
    3
    -1
    3

    思路

      这题Floyd肯定是不能做的,考虑其他办法。

      类似于静态树上求节点之间的最小边权可做。

      显然这颗静态树的边权要尽可能的大,且注意到很多较小的重边是不用去跑的,所以考虑只把最大的边加入连通块,舍弃小的重边。

      对于两座城市,如果不在同一个连通块内,当然是不能跑的,输出-1;

      如果在同一个连通块内,因为边点和询问的数量级过大,显然正常的枚举是不足以胜任此题要求的。

      这就涉及到静态树上求节点之间的最小边权问题。

      对于这种问题,可以上树链剖分用线段树来维护,也可以用树上问题的经典解法LCA来求解。

      在处理 f 数组的过程中维护一个 dis 数组用以表示点间最小边权值即可。

    CODE

      1 #include <bits/stdc++.h>
      2 #define dbg(x) cout << #x << "=" << x << endl
      3 #define eps 1e-8
      4 #define pi acos(-1.0)
      5 
      6 using namespace std;
      7 typedef long long LL;
      8 
      9 template<class T>inline void read(T &res)
     10 {
     11     char c;T flag=1;
     12     while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
     13     while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
     14 }
     15 
     16 namespace _buff {
     17     const size_t BUFF = 1 << 19;
     18     char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
     19     char getc() {
     20         if (ib == ie) {
     21             ib = ibuf;
     22             ie = ibuf + fread(ibuf, 1, BUFF, stdin);
     23         }
     24         return ib == ie ? -1 : *ib++;
     25     }
     26 }
     27 
     28 int qread() {
     29     using namespace _buff;
     30     int ret = 0;
     31     bool pos = true;
     32     char c = getc();
     33     for (; (c < '0' || c > '9') && c != '-'; c = getc()) {
     34         assert(~c);
     35     }
     36     if (c == '-') {
     37         pos = false;
     38         c = getc();
     39     }
     40     for (; c >= '0' && c <= '9'; c = getc()) {
     41         ret = (ret << 3) + (ret << 1) + (c ^ 48);
     42     }
     43     return pos ? ret : -ret;
     44 }
     45 
     46 const int maxn = 1e5 + 7;
     47 
     48 int n, m, cnt;
     49 int head[maxn << 1], edge[maxn << 1], nxt[maxn << 1];
     50 int fa[maxn], f[maxn][30], depth[maxn], w[maxn << 1];
     51 int dis[maxn][30];
     52 
     53 bool vis[maxn];
     54 
     55 struct node {
     56     int u, v, w;
     57 } e[maxn << 1];
     58 
     59 bool cmp(node a, node b) {
     60     return a.w > b.w;
     61 }
     62 
     63 void BuildGraph(int u, int v, int c) {
     64     cnt++;
     65     edge[cnt] = v;
     66     nxt[cnt] = head[u];
     67     w[cnt] = c;
     68     head[u] = cnt;
     69 }
     70 
     71 int fid(int x) {
     72     return x == fa[x] ? x : fid(fa[x]);
     73 }
     74 
     75 void join() {
     76     sort(e+1, e+m+1, cmp);
     77     for ( int i = 1; i <= n; ++i ) {
     78         fa[i] = i;
     79     }
     80     for ( int i = 1; i <= m; ++i ) {
     81         int eu = fid(e[i].u), ev = fid(e[i].v);
     82         if(eu != ev) {
     83             fa[eu] = ev;
     84             BuildGraph(e[i].u, e[i].v, e[i].w);
     85             BuildGraph(e[i].v, e[i].u, e[i].w);
     86             //dbg(e[i].w);
     87         }
     88     }
     89 }
     90 
     91 void dfs(int x) {//找x和y的最近公共祖先
     92     vis[x] = 1;
     93     for ( int i = head[x]; i; i = nxt[i] ) {
     94         int y = edge[i];
     95         if(!vis[y]) {
     96             depth[y] = depth[x] + 1;
     97             f[y][0] = x;//y向上跳肯定是x
     98             dis[y][0] = w[i];
     99             dfs(y);
    100         }
    101     }
    102 }
    103 
    104 int lca(int x, int y) {//查找xy的最近公共祖先
    105     int ans = 0x3f3f3f3f;
    106     if(fid(x) != fid(y)) {
    107         return -1;
    108     }
    109     if(depth[x] < depth[y])
    110         swap(x, y);//保证x是比y深的
    111     for ( int i = 20; i >= 0; --i ) {
    112         if(depth[f[x][i]] >= depth[y]) {//让x跳到和y同一层
    113             ans = min(ans, dis[x][i]);
    114             x = f[x][i];
    115         }
    116     }
    117     if(x == y) {///重合态
    118         return ans;
    119     }
    120     for ( int i = 20; i >= 0; --i ) {///不重合一起跳
    121         if(f[x][i] != f[y][i]) {//父亲不同要跳一步
    122             ans = min(ans, min(dis[y][i], dis[x][i]));
    123             x = f[x][i], y = f[y][i];
    124         }
    125     }
    126     ans = min(ans, min(dis[x][0], dis[y][0]));
    127     return ans;///跳完最后一步
    128 }
    129 
    130 int main()
    131 {
    132     scanf("%d %d", &n, &m);
    133     for ( int i = 1; i <= m; ++i ) {
    134         scanf("%d %d %d",&e[i].u, &e[i].v, &e[i].w);
    135     }
    136     join();
    137     for ( int i = 1; i <= n; ++i ) {
    138         if(!vis[i]) {
    139             depth[i] = 1;
    140             dfs(i);
    141             f[i][0] = i;
    142             dis[i][0] = 0x3f3f3f3f;
    143         }
    144     }
    145     for ( int i = 1; i <= 20; ++i ) {
    146         for ( int j = 1; j <= n; ++j ) {
    147             f[j][i] = f[f[j][i - 1]][i - 1];
    148             dis[j][i] = min(dis[j][i - 1], dis[f[j][i - 1]][i - 1]);
    149             //printf("dis[%d][%d]:%d
    ",j,i-1,dis[j][i-1]);
    150             //printf("dis[%d][%d]:%d
    
    ",fa[j][i-1],i-1,dis[fa[j][i-1]][i-1]);
    151         }
    152     }
    153     int q;
    154     cin >> q;
    155     for ( int i = 1; i <= q; ++i ) {
    156         int x, y;
    157         scanf("%d %d", &x, & y);
    158         printf("%d
    ",lca(x,y));
    159     }
    160     return 0;
    161 }
    View Code
  • 相关阅读:
    浅谈CLR CTS CLS。。。
    "每日一道面试题".net托管堆是否会存在内存泄漏的情况
    “每日一道面试题”.Net中GC的运行机制
    “每日一道面试题”.Net中所有类的基类是以及包含的方法
    c# 逆波兰式实现计算器
    c#控制台实现post网站登录
    c#读取xml文件
    .net md5
    ado.net知识整理
    第八章:Python高级编程-迭代器和生成器
  • 原文地址:https://www.cnblogs.com/orangeko/p/12369325.html
Copyright © 2011-2022 走看看