• vijos 运输计划


    Description

    公元 2044 年,人类进入了宇宙纪元。L 国有 n 个星球,还有 n−1 条双向航道,每条航道建立在两个星球之间,这 n−1 条航道连通了 L 国的所有星球。小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之间不会产生任何干扰。为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后,这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

     

    Input

    第一行包括两个正整数 n,m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。接下来 n−1 行描述航道的建设情况,其中第 i 行包含三个整数 ai,bi 和 ti,表示第 i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。数据保证 1≤ai,bi≤n 且 0≤ti≤1000。接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j 个运输计划是从 uj 号星球飞往 vj号星球。数据保证 1≤ui,vi≤n

     

    Output

    输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

     

    Sample Input

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

    Sample Output

    11

    Hint

    将第 1 条航道改造成虫洞: 则三个计划耗时分别为:11,12,11,故需要花费的时间为 12。

    将第 2 条航道改造成虫洞: 则三个计划耗时分别为:7,15,11,故需要花费的时间为 15。

    将第 3 条航道改造成虫洞: 则三个计划耗时分别为:4,8,11,故需要花费的时间为 11。

    将第 4 条航道改造成虫洞: 则三个计划耗时分别为:11,15,5,故需要花费的时间为 15。

    将第 5 条航道改造成虫洞: 则三个计划耗时分别为:11,10,6,故需要花费的时间为 11。

    故将第 3 条或第 5 条航道改造成虫洞均可使得完成阶段性工作的耗时最短,需要花费的时间为 11。

     (原题传送门[here])


      首先需要求LCA,把所有询问的求的LCA和出发点,结束点保存下来。

      然后二分答案。判断是否可以把耗时大于它的航线的用时缩短到小于等于二分值。

      这个判定就用差分,先在数组中将LCA的值-2,出发点和结束点的值分别+1,从叶节点向上累加。

      关于判定就找1个所有需要改的航线都覆盖了的边。并且使耗时的最大值要不超过二分值,这样样就行了。否则说明还会有航线的值大于二分值。

      另外注意常数对算法的影响,理论复杂度O(n + m + nlog2L)。(L是树上最长链的长度)

    Code

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>    
      4 #include<cctype>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<map>
      8 #include<set>
      9 #include<queue>
     10 #include<stack>
     11 #include<vector>
     12 using namespace std;
     13 #define smin(a, b) a = min(a, b)
     14 #define smax(a, b) a = max(a, b)
     15 typedef bool boolean;
     16 template<typename T>
     17 inline void readInteger(T& u){
     18     char x;
     19     while(!isdigit((x = getchar())));
     20     for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
     21     ungetc(x, stdin);
     22 }
     23 
     24 typedef class Edge{
     25     public:
     26         int end;
     27         int next;
     28         int w;
     29         Edge(const int end = 0, const int next = 0, const int w = 0):end(end), next(next), w(w){}
     30 }Edge;
     31 
     32 typedef class MapManager{
     33     public:
     34         int ce;
     35         int* h;
     36         Edge* edge;
     37         MapManager(){}
     38         MapManager(int points, int edges):ce(0){
     39             h = new int[(const int)(points + 1)];
     40             edge = new Edge[(const int)(edges + 1)];
     41             memset(h, 0, sizeof(int) * (points + 1));
     42         }
     43         inline void addEdge(int from, int end, int w){
     44             edge[++ce] = Edge(end, h[from], w);
     45             h[from] = ce;
     46         }
     47         inline void addDoubleEdge(int from, int end, int w){
     48             addEdge(from, end, w);
     49             addEdge(end, from, w);
     50         }
     51 }MapManager;
     52 
     53 #define m_begin(g, i) (g).h[(i)]
     54 #define m_end(g, i) (g).edge[(i)].end
     55 #define m_next(g, i) (g).edge[(i)].next
     56 #define m_w(g, i) (g).edge[(i)].w
     57 
     58 template<typename T>class Matrix{
     59     public:
     60         T *p;
     61         int lines;
     62         int rows;
     63         Matrix():p(NULL){    }
     64         Matrix(int lines, int rows):lines(lines), rows(rows){
     65             p = new T[(lines * rows)];
     66         }
     67         T* operator [](int pos){
     68             return (p + pos * lines);
     69         }
     70 };
     71 #define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows)
     72 
     73 typedef class union_found{
     74     public:
     75         int *f;
     76         union_found():f(NULL) {}
     77         union_found(int points) {
     78             f = new int[(const int)(points + 1)];
     79         }
     80         int find(int x) {
     81             if(f[x] != x)    return f[x] = find(f[x]);
     82             return f[x];
     83         }
     84         int& operator [](int pos){
     85             return f[pos];
     86         }
     87 }union_found;
     88 
     89 #define BZ_MAX 19
     90 
     91 typedef class query{
     92     public:
     93         int from;
     94         int end;
     95         int minv;
     96         int lca;
     97         query(const int from = 0, const int end = 0, const int lca = 0, const int minv = 0):from(from), lca(lca), end(end), minv(minv){}
     98         boolean operator <(query another) const {
     99             return this->minv < another.minv;
    100         }
    101         
    102 }query;
    103 
    104 boolean operator <(int val, query a){
    105     return val < a.minv;
    106 }
    107 int n, q;
    108 int cq;
    109 int* times;
    110 int* up;
    111 int* dis;
    112 MapManager g;
    113 boolean* visited;
    114 boolean* enable;
    115 query *results;
    116 MapManager mq;
    117 union_found uf;
    118 
    119 inline void init(){
    120     readInteger(n);
    121     readInteger(q);
    122     g = MapManager(n, 2 * n);
    123     mq = MapManager(n, 2 * q);
    124     for(int i = 1, a, b, c; i < n; i++){
    125         readInteger(a);
    126         readInteger(b);
    127         readInteger(c);
    128         g.addDoubleEdge(a, b, c);
    129     }
    130     for(int i = 1, a, b; i <= q; i++){
    131         readInteger(a);
    132         readInteger(b);
    133         mq.addDoubleEdge(a, b, 1);
    134     }
    135 }
    136 
    137 void dfs(int node, int last, int distance){
    138     up[node] = last;
    139     dis[node] = distance;
    140     for(int i = m_begin(g, node); i != 0; i = m_next(g, i)){
    141         int &e = m_end(g, i);
    142         if(e == last)    continue;
    143         dfs(e, node, m_w(g, i) + distance);
    144     }
    145 }
    146 
    147 inline void init_dfs(){
    148     up = new int[(const int)(n + 1)];
    149     dis = new int[(const int)(n + 1)];
    150     uf = union_found(n + 1);
    151     visited = new boolean[(const int)(n + 1)];
    152     enable = new boolean[(const int)(q * 2 + 1)];
    153     memset(up, 0, sizeof(int) * (n + 1));
    154     memset(enable, true, sizeof(boolean) * (q * 2 + 1));
    155     memset(visited, false, sizeof(boolean) * (n + 1));
    156     dfs(1, 0, 0);
    157 }
    158 
    159 int cal_length(int a, int b, int lca){
    160     return dis[a] + dis[b] - (dis[lca] << 1);
    161 }
    162 
    163 void tarjan(int node){
    164     uf[node] = node;
    165     visited[node] = true;
    166     for(int i = m_begin(g, node); i != 0; i = m_next(g, i)){
    167         int& e = m_end(g, i);
    168         if(!visited[e]){
    169             tarjan(e);
    170             uf[e] = node;
    171         }
    172     }
    173     for(int i = m_begin(mq, node); i != 0; i = m_next(mq, i)){
    174         int& e = m_end(mq, i);
    175         if(visited[e] && enable[i]){
    176             int lca = uf.find(e);
    177             results[++cq] = query(node, e, lca, cal_length(node, e, lca));
    178             enable[i] = enable[i + ((i & 1) ? (1) : (-1))] = false;
    179         }
    180     }
    181 }
    182 
    183 boolean update(int node, int limit, int maxer, int minx){
    184     for(int j = m_begin(g, node); j != 0; j = m_next(g, j)){
    185         int& e = m_end(g, j);
    186         if(e == up[node])    continue;
    187         if(update(e, limit, maxer, minx))    return true;
    188         times[node] += times[e];
    189     }
    190     if(times[node] == limit){
    191         if(maxer - cal_length(node, up[node], up[node]) <= minx){
    192             return true;
    193         }
    194     }
    195     return false;
    196 }
    197 
    198 boolean check(int minx){
    199     int counter = 0;
    200     int maxer = 0;
    201     memset(times, 0, sizeof(int) * (n + 1));
    202     query* it = upper_bound(results + 1, results + q + 1, minx);
    203     for(; it != results + q + 1; it++){
    204         times[it->from]++;
    205         times[it->end]++;
    206         times[it->lca]++;
    207         counter++;
    208         smax(maxer, it->minv);
    209     }
    210     return update(1, counter, maxer, minx);
    211 }
    212 
    213 inline void solve(){
    214     int l = 0, r;
    215     results = new query[(const int)(q + 1)];
    216     tarjan(1);
    217     delete[] visited;
    218     delete[] uf.f;
    219     times = new int[(const int)(n + 1)];
    220     sort(results + 1, results + q + 1);
    221     r = results[q].minv;
    222     while(l <= r){
    223         int mid = l + ((r - l) >> 1);
    224         if(check(mid))    r = mid - 1;
    225         else l = mid + 1;
    226     }
    227     printf("%d", r + 1);
    228 }
    229 
    230 int main(){
    231     init();
    232     init_dfs();
    233     solve();
    234     return 0;
    235 }

    (PS:这道题很神奇,vijos过了,codevs的最后一个点TLE)

  • 相关阅读:
    20189317 《网络攻防技术》 第四周作业
    20189317 《网络攻防技术》 第三周作业
    20189317 《网络攻防技术》 第二周作业
    2018-2019-2 20189317 《网络攻防技术》 第一周作业
    20189311《网络攻防》第十周作业
    20189311《网络攻防》第九周作业
    20189311《网络攻防》第八周作业
    20189311《网络攻防》第七周作业
    20189311《网络攻防》第六周作业
    20189311《网络攻防》第五周作业
  • 原文地址:https://www.cnblogs.com/yyf0309/p/6128871.html
Copyright © 2020-2023  润新知