zoukankan      html  css  js  c++  java
  • [NOIP2015] 运输计划

    题目背景

    公元 2044 年,人类进入了宇宙纪元。

    题目描述

    L 国有 n 个星球,还有 n-1 条双向航道,每条航道建立在两个星球之间,这 n-1 条航道连通了 L 国的所有星球。

    小 P 掌管一家物流公司,该公司有很多个运输计划,每个运输计划形如:有一艘物

    流飞船需要从 ui 号星球沿最快的宇航路径飞行到 vi 号星球去。显然,飞船驶过一条航道 是需要时间的,对于航道 j,任意飞船驶过它所花费的时间为 tj,并且任意两艘飞船之 间不会产生任何干扰。

    为了鼓励科技创新,L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小 P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

    在虫洞的建设完成前小 P 的物流公司就预接了 m 个运输计划。在虫洞建设完成后, 这 m 个运输计划会同时开始,所有飞船一起出发。当这 m 个运输计划都完成时,小 P 的 物流公司的阶段性工作就完成了。

    如果小 P 可以自由选择将哪一条航道改造成虫洞,试求出小 P 的物流公司完成阶段 性工作所需要的最短时间是多少?

    输入输出格式

    输入格式:

    输入文件名为 transport.in。

    第一行包括两个正整数 n、m,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 1 到 n 编号。

    接下来 n-1 行描述航道的建设情况,其中第 i 行包含三个整数 ai, bi 和 ti,表示第

    i 条双向航道修建在 ai 与 bi 两个星球之间,任意飞船驶过它所花费的时间为 ti。

    接下来 m 行描述运输计划的情况,其中第 j 行包含两个正整数 uj 和 vj,表示第 j个 运输计划是从 uj 号星球飞往 vj 号星球。

    输出格式:

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

    输入输出样例

    输入样例#1:
    6 3 
    1 2 3 
    1 6 4 
    3 1 7 
    4 3 6 
    3 5 5 
    3 6 
    2 5 
    4 5
    输出样例#1:
    11

    说明

    所有测试数据的范围和特点如下表所示

    请注意常数因子带来的程序效率上的影响。

    模型:给出一棵树,给出树上的一些路径,要你删除一条边使得最大路径最小

    题解:

    LCA+二分+树上差分

    先求出所有任务路径的长度(O(mlogn))

    二分,找出所有大于mid的任务路径,考虑删除一条边使得最大任务路径<=mid

    要删的一定是所有任务路径都经过的权值最大的边

    树上差分,对于一条任务路径(u,v),cnt[u]+=1,cnt[v]+=1,cnt[lca(u,v)]-=2,再跑一遍dfs找出cnt[x]==任务路径数的边(O(logL*(m+n),L=1000)

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<cmath>
      6 #include<algorithm>
      7 #define ll long long
      8 #define RG register
      9 using namespace std;
     10 
     11 const int maxn = 300010;
     12 
     13 int n,m,mxl,ans=1<<30;
     14 int nxt[maxn*2],to[maxn*2],w[maxn*2],h[maxn],e_num;
     15 int fa[maxn],dep[maxn],top[maxn],siz[maxn],son[maxn],dist[maxn],way[maxn];
     16 int cnt[maxn],tot,mx,mx1;
     17 struct NODE {
     18   int x,y,l;
     19 }task[maxn];
     20 
     21 int gi() {
     22   int x=0; char ch=getchar();
     23   while(ch<'0' || ch>'9') ch=getchar();
     24   while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();}
     25   return x;
     26 }
     27 
     28 inline void add(int x, int y, int z) {nxt[++e_num]=h[x],to[e_num]=y,w[e_num]=z,h[x]=e_num;}
     29 
     30 inline void dfs1(int u) {
     31   siz[u]=1;
     32   for(int i=h[u]; i; i=nxt[i]) {
     33     int v=to[i];
     34     if(v==fa[u]) continue;
     35     fa[v]=u,dep[v]=dep[u]+1,dist[v]=dist[u]+w[i],way[v]=w[i];
     36     dfs1(v);
     37     if(siz[v]>siz[son[u]]) son[u]=v;
     38     siz[u]+=siz[v];
     39   }
     40 }
     41 
     42 inline void dfs2(int u) {
     43   if(son[u]) top[son[u]]=top[u],dfs2(son[u]);
     44   for(int i=h[u]; i; i=nxt[i]) {
     45     int v=to[i];
     46     if(v==fa[u] || v==son[u]) continue;
     47     top[v]=v,dfs2(v);
     48   }
     49 }
     50 
     51 inline int lca(int x, int y) {
     52   while(top[x]!=top[y]) {
     53     if(dep[top[x]]>dep[top[y]]) x=fa[top[x]];
     54     else y=fa[top[y]];
     55   }
     56   if(dep[x]<dep[y]) return x;
     57   else return y;
     58 }
     59 
     60 inline int dfs3(int u) {
     61   for(int i=h[u]; i; i=nxt[i]) {
     62     int v=to[i];
     63     if(v==fa[u]) continue;
     64     cnt[u]+=dfs3(v);
     65   }
     66   if(cnt[u]==tot) mx1=max(mx1,way[u]);
     67   return cnt[u];
     68 }
     69 
     70 inline bool check(int k) {
     71   memset(cnt,0,sizeof(cnt));
     72   mx=mx1=tot=0;
     73   for(int i=1; i<=m; i++) {
     74     if(task[i].l>k) {
     75       mx=max(mx,task[i].l);
     76       cnt[task[i].x]+=1,cnt[task[i].y]+=1,cnt[lca(task[i].x,task[i].y)]-=2;
     77       tot++;
     78     }
     79   }
     80   dfs3(1);
     81   return mx-mx1<=k;
     82 }
     83 
     84 int main() {
     85   n=gi(),m=gi();
     86   for(RG int i=1; i<n; i++) {
     87     int x=gi(),y=gi(),z=gi();
     88     add(x,y,z),add(y,x,z);
     89   }
     90   dep[1]=1,fa[1]=1,top[1]=1;
     91   dfs1(1),dfs2(1);
     92   for(RG int i=1; i<=m; i++) {
     93     int x=gi(),y=gi();
     94     task[i].x=x,task[i].y=y;
     95     task[i].l=dist[x]+dist[y]-2*dist[lca(x,y)];
     96     mxl=max(mxl,task[i].l);
     97   }
     98   int l=0,r=mxl,mid;
     99   l=max(r-1000,0);
    100   while(l<=r) {
    101     mid=(l+r)>>1;
    102     if(check(mid)) ans=min(ans,mid),r=mid-1;
    103     else l=mid+1;
    104   }
    105   printf("%d", ans);
    106   return 0;
    107 }

    总结:

    1、树上差分算路径的交

    2、从根dfs到叶子,回溯时返回子孙的信息

    3、不要无脑设二分上下界,保证正确性的情况下尽量使二分次数变少

  • 相关阅读:
    高并发秒杀系统架构设计 · 抢购、微信红包、一元夺宝
    Linux服务器集群系统(一)
    keepalived+nginx双机热备+负载均衡
    kafka的一些常用命令
    基于Keepalived实现LVS双主高可用集群
    如何生动形象、切中要点地讲解 OSI 七层模型和两主机传输过程
    MyBatis动态SQL foreach标签实现批量插入
    详解Vue生命周期
    centos 解压压缩包到指定目录
    门罗币(MONERO)钱包生成教程
  • 原文地址:https://www.cnblogs.com/HLXZZ/p/7278198.html
Copyright © 2011-2022 走看看