【noip2018】【luogu5021】赛道修建

题目描述

C 城将要举办一系列的赛车比赛。在比赛前,需要在城内修建 mm 条赛道。

C 城一共有 nn 个路口,这些路口编号为 1,2,…,n1,2,,n,有 n-1n1 条适合于修建赛道的双向通行的道路,每条道路连接着两个路口。其中,第 ii 条道路连接的两个路口编号为 a_iai  b_ibi,该道路的长度为 l_ili。借助这 n-1n1 条道路,从任何一个路口出发都能到达其他所有的路口。

一条赛道是一组互不相同的道路 e_1,e_2,…,e_ke1,e2,,ek,满足可以从某个路口出发,依次经过 道路 e_1,e_2,…,e_ke1,e2,,ek(每条道路经过一次,不允许调头)到达另一个路口。一条赛道的长度等于经过的各道路的长度之和。为保证安全,要求每条道路至多被一条赛道经过。

目前赛道修建的方案尚未确定。你的任务是设计一种赛道修建的方案,使得修建的 mm 条赛道中长度最小的赛道长度最大(即 mm 条赛道中最短赛道的长度尽可能大)

输入输出格式

输入格式:

 

输入文件第一行包含两个由空格分隔的正整数 n,mn,m,分别表示路口数及需要修建的 赛道数。

接下来 n-1n1 行,第 ii 行包含三个正整数 a_i,b_i,l_iai,bi,li,表示第 ii 条适合于修建赛道的道 路连接的两个路口编号及道路长度。保证任意两个路口均可通过这 n-1n1 条道路相互到达。每行中相邻两数之间均由一个空格分隔。

 

输出格式:

 

输出共一行,包含一个整数,表示长度最小的赛道长度的最大值。

 

输入输出样例

输入样例#1:   复制
7 1 
1 2 10 
1 3 5 
2 4 9 
2 5 8 
3 6 6 
3 7 7
输入样例#2:   复制
9 3 
1 2 6 
2 3 3 
3 4 5 
4 5 10 
6 2 4 
7 2 9 
8 4 7 
9 4 4
输出样例#2:   复制
15

 

输出样例#1:   复制
31

 

 

 

 

 

 

 

 

【数据规模与约定】

对于所有的数据, 2 ≤ n ≤ 50,0002n50,000 1 ≤ m ≤ n-11mn1 1 ≤ a_i,b_i ≤ n1ai,bin 1 ≤ l_i ≤ 10,0001li10,000

题解:

       题意即求一个k段不相交路径长度最小值的最大值;

       二分这个最大的最小值mid,那么要求判断是否有一种方案可以分出>=k条路径使得权值都>=mid;

      树形dp  : 当做到节点u,要么u的所有儿子都一定成为了路径,要么至多有一条可以向上延伸的路径;

      这样如果可以在u形成>=mid的路径,那么一定比此时不形成路径往上连更优;

      记录每个点可以往上连的权值val,考虑u的儿子v,u,v之间的边为E[i]  (代码风格,忍受一下。。)

      val[v]+E[i].w >= mid 直接统计为一条合法路径;

      否则把左边存在一个数组里,可以知道要形成路径只能两两配对,排序后二分可以确定最大的对数;

      注意未配对的最大的数可能可以替换已配对的权值,找到最大可替换数设置成val[u](注意细节)

      复杂度   $O(n log^2 n)$

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<vector>
 4 #include<algorithm>
 5 #define inf 0x3f3f3f3f
 6 #define rg register 
 7 #define il inline 
 8 #define Run(i,l,r) for(int i=l;i<=r;i++)
 9 using namespace std;
10 const int N=50500;
11 int n,k,o,hd[N],mid,val[N],sum,p[N];
12 vector<int>g[N];
13 struct Edge{int v,nt,w;}E[N<<1];
14 void adde(int u,int v,int w){
15     E[o]=(Edge){v,hd[u],w};hd[u]=o++;
16     E[o]=(Edge){u,hd[v],w};hd[v]=o++; 
17 }
18 bool check2(int u,int Mid){
19     int cnt=g[u].size();
20     int p=cnt-(Mid<<1); 
21     for(int i=1;i<=Mid;i++){
22         if(g[u][p+i-1]+g[u][cnt-i]<mid)return false;
23     }
24     return true;
25 }
26 void dfs(int u,int fa){
27     g[u].clear();
28     val[u]=0;
29     for(int i=hd[u];i;i=E[i].nt){
30         int v=E[i].v;
31         if(v==fa)continue;
32         dfs(v,u);
33         int t=E[i].w+val[v];
34         if(t>=mid)sum++;
35         else g[u].push_back(t); 
36     }
37     int cnt=(int)g[u].size();
38     if(!cnt)return;
39     sort(g[u].begin(),g[u].end());
40     int l=0,r=cnt>>1;
41     while(l<r){
42         int Mid=(l+r+1)>>1;
43         if(check2(u,Mid))l=Mid;
44         else r=Mid-1;
45     }
46     sum+=l;
47     if((l<<1)==cnt)return;
48     for(int i=0;i<l;i++){
49         int t1=cnt-(l<<1)+i;
50         int t2=cnt-1-i;
51         p[t1]=t2;
52         p[t2]=t1;
53     }
54     int t;
55     for(t=cnt-(l<<1);t<cnt&&g[u][t-1]+g[u][p[t]]>=mid;t++){
56         p[p[t]]=t-1;
57         p[t-1]=p[t]; 
58     }
59     t--;
60     return void(val[u]=g[u][t]);
61 }
62 bool check1(){
63     sum=0;dfs(1,0);
64     return sum>=k;
65 }
66 int main(){
67     freopen("track.in","r",stdin);
68     freopen("track.out","w",stdout);
69     scanf("%d%d",&n,&k);
70     int l=inf,r=0;
71     o=1;
72     for(rg int i=1,u,v,w;i<n;i++){
73         scanf("%d%d%d",&u,&v,&w);
74         r+=w; l=min(l,w);
75         adde(u,v,w);
76     }
77     while(l<r){
78         mid=(l+r+1)>>1;
79         if(check1())l=mid;
80         else r=mid-1;
81     }
82     printf("%d\n",l);
83 }//by tkys_Austin;
View Code

 

 

 

 

猜你喜欢

转载自www.cnblogs.com/Paul-Guderian/p/10014642.html