zoukankan      html  css  js  c++  java
  • 洛谷P2680(树上差分+二分)

    洛谷P2680:运输计划

    题目背景

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

    题目描述

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

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

    小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_iui 号星球沿最快的宇航路径飞行到 v_ivi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 jj,任意飞船驶过它所花费的时间为 t_jtj,并且任意两艘飞船之间不会产生任何干扰。

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

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

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

    输入输出格式

    输入格式:

     

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

    接下来 n-1n1 行描述航道的建设情况,其中第 ii 行包含三个整数 a_i, b_iai,bi 和 t_iti,表示第 ii 条双向航道修建在 a_iai与 b_ibi 两个星球之间,任意飞船驶过它所花费的时间为 t_iti。数据保证 1 leq a_i,b_i leq n1ai,bin 且 0 leq t_i leq 10000ti1000。

    接下来 mm 行描述运输计划的情况,其中第 jj 行包含两个正整数 u_juj 和 v_jvj,表示第 jj 个运输计划是从 u_juj 号星球飞往 v_jvj号星球。数据保证 1 leq u_i,v_i leq n1ui,vin

     

    输出格式:

     

    一个整数,表示小 PP 的物流公司完成阶段性工作所需要的最短时间。

     

    输入输出样例

    输入样例#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

    说明

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

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

    思路:二分查找答案,二分判断条件是这条路径的长度都小于mid或者大于mid的路径用差分数组维护后求出每条线段被走过几次,走过次数等于大于mid的路径数的就是可以被更改的线段,然后再其中找到最大的那条,用最长路径 - 这个值,如果小于等于mid则成立。

    如果TLE了一个样例,那就O2+多交几次,网速快的话好像能AC。

    什么都不说了,都在代码里。

      1 ///用vector存图比前象星要慢
      2 #include<cstdio>
      3 #include<string.h>
      4 #include<algorithm>
      5 using namespace std;
      6 inline int scan()
      7 {
      8     int x=0,c=1;
      9     char ch=' ';
     10     while((ch>'9'||ch<'0')&&ch!='-')ch=getchar();
     11     while(ch=='-')c*=-1,ch=getchar();
     12     while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
     13     return x*c;
     14 }
     15 const int maxn=3e5+5;
     16 const int maxnbits=20;
     17 int n,m,num,ret,Max,tol;
     18 int depth[maxn],father[maxn][maxnbits],lg[maxn],dis[maxn],len[maxn],sum[maxn],head[maxn<<1];
     19 struct edge{
     20     int to;
     21     int next;
     22     int w;
     23 }e[maxn<<1];
     24 struct node{
     25     int x,y;
     26 }nd[maxn];
     27 void add(int s,int t,int w){
     28     tol++;
     29     e[tol].to=t;
     30     e[tol].next=head[s];
     31     e[tol].w=w;
     32     head[s]=tol;
     33 }
     34 int v[maxn];
     35 void dfs(int nowp,int fa){
     36     depth[nowp]=depth[fa]+1;
     37     father[nowp][0]=fa;
     38     for(int i=1;i<=lg[depth[nowp]]+1;i++){
     39         father[nowp][i]=father[father[nowp][i-1]][i-1];
     40     }
     41     for(int i=head[nowp];i;i=e[i].next){
     42         int to=e[i].to;
     43         if(to!=fa){
     44             dis[to]=dis[nowp]+e[i].w;
     45             v[to]=e[i].w;
     46             dfs(to,nowp);
     47         }
     48     }
     49 }
     50 int LCA(int a,int b){
     51     if(depth[a]<depth[b]){
     52         swap(a,b);
     53     }
     54     while(depth[a]!=depth[b]){
     55         a=father[a][lg[depth[a]-depth[b]]];
     56     }
     57     if(a==b) return a;
     58     for(int i=lg[depth[a]];i>=0;i--){
     59         if(father[a][i]!=father[b][i]){
     60             a=father[a][i];
     61             b=father[b][i];
     62         }
     63     }
     64     return father[a][0];
     65 }
     66 void DFS(int nowp,int fa){
     67     for(int i=head[nowp];i;i=e[i].next){
     68         int to=e[i].to;
     69         if(to!=fa){
     70             DFS(to,nowp);
     71             sum[nowp]+=sum[to];///从叶子节点进行求前缀和
     72         }
     73     }
     74     if(sum[nowp]==num){///sum[nowp]是nowp点的边被num条路径走过几次,如果走过次数等于num,则可对这条边进行更改
     75         ret=max(ret,v[nowp]);///记录可更改最大边
     76     }
     77 }
     78 bool check(int mid){
     79     num=0;
     80     ret=0;
     81     memset(sum,0,sizeof(sum));
     82     for(int i=0;i<m;i++){
     83         if(len[i]>mid){///这条路径是否比mid大,如果大,则可对其的某跳边进行更改
     84             num++;
     85             int lca=LCA(nd[i].x,nd[i].y);
     86             sum[nd[i].x]++,sum[nd[i].y]++,sum[lca]-=2;///差分记录这条路径的所有边可进行更改
     87         }
     88     }
     89     if(!num) return true;///如果没有比mid大的路径,那么它就是合法路径(mid)
     90     DFS(1,0);///否则对能更改的路径进行更改
     91     return Max-ret<=mid;///如果最长路径-能更改的最大边小于等于mid,则这个mid合法
     92 }
     93 int main(){
     94     lg[0]=-1;
     95     for(int i=1;i<maxn-2;i++){
     96         lg[i]=lg[i>>1]+1;
     97     }
     98     int a,b,t;
     99     int l=0,r=-1;
    100     n=scan();
    101     m=scan();
    102     for(int i=0;i<n-1;i++){
    103         a=scan();
    104         b=scan();
    105         t=scan();
    106         add(a,b,t);
    107         add(b,a,t);
    108     }
    109     dfs(1,0);
    110     for(int i=0;i<m;i++){
    111         a=scan();
    112         b=scan();
    113         nd[i]={a,b};
    114         int lca=LCA(a,b);
    115         len[i]=dis[a]+dis[b]-2*dis[lca];///计算a-b的距离
    116         r=max(r,len[i]);///查找最大的路径长度,做二分最大值
    117         Max=r;
    118     }
    119     int ans=0;
    120     while(l<=r){
    121         int mid=(l+r)>>1;
    122         if(check(mid)){///如果这个mid符合条件,则找更小的,看能否找到符合条件的
    123             r=mid-1;
    124             ans=mid;
    125         }else{
    126             l=mid+1;
    127         }
    128     }
    129     printf("%d
    ",ans);
    130     return 0;
    131 }
    View Code
  • 相关阅读:
    python基础(五)——CGI编程
    python基础(六)——mysql的使用
    python基础(七)——网络编程
    python基础(八)——多线程
    python面试题
    linux日志管理
    linux之nagios安装教程
    【华为云技术分享】盘点物联网常用开发板
    数据库“意外失联”?华为云DRS异地多活灾备为您支招
    如何处理暗数据?
  • 原文地址:https://www.cnblogs.com/liuzuolin/p/10878566.html
Copyright © 2011-2022 走看看