bzoj 3246 [Ioi2013]Dreaming 贪心
[Ioi2013]Dreaming
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 638 Solved: 241
[Submit][Status][Discuss]
Description
Serpent(水蛇)生活的地方有N个水坑,编号为0,...,N - 1,有M条双向小路连接这些水坑。每两个水坑之间至多有一条路径(路径包含一条或多条小路)相互连接,有些水坑之间根本无法互通(即M ≤ N-1 )。Serpent走过每条小路需要一个固定的天数,不同的小路需要的天数可能不同。Serpent的朋友袋鼠希望新修 N - M - 1条小路,让Serpent可以在任何两个水坑间游走。袋鼠可以在任意两个水坑之间修路,Serpent通过每条新路的时间都是L天。袋鼠希望找到一种修路方式使得修路之后Serpent在每两个水坑之间游走的最长时间最短。
举例说明
上图中有12个水坑8条小路( N = 12, M = 8)。假如L = 2 ,即Serpent通过任何一条新路都需要2天。那么,袋鼠可以修建3条新路:
水坑1和水坑2之间;
水坑1和水坑6之间;
水坑4和水坑10之间。
上图显示了修路后的最终状态。从水坑0走到水坑11的时间最长,需要18天。这是 最佳结果,无论袋鼠如何选择修路方式,总会存在一些水坑对,Serpent需要18天 或者更长时间从其中一个走到另一个。
Input
N : 水坑的数目。
M : 原本存在的小路的数目。
L : Serpent通过新修的路经的时间。
A, B 和 T: 三个包含M个元素的数组,分别表示每条小路的两个端点和通过这条小路的时间。例如,第i条小路连接水坑 A[i-1]和水坑B[i-1],通过这条小路的时间是T[i-1]天。
Output
如上所述,表示游走于两个距离最远的水坑之间所需的时间。
Sample Input
0 8 4
8 2 2
2 7 4
5 11 3
5 1 7
1 3 1
1 9 5
10 6 3
Sample Output
HINT
n <= 500000
题目大意
给定n个点m条边的森林,每条边有边权。要求用长度为L的边把它连成一棵树,且直径最小。
n≤500000
分析
首先对于森林中每一棵树,它只有一条路径可能会对答案有贡献。为了使答案尽量小,那就要使这个值尽量小。那么可以选择它的所有点中,到达其它点距离最大值最小的,去和其它树连接。然后这个点对答案的贡献就是这个距离。
那么会发现,这些数看成一个点之后,又会连成一棵树。
由于这棵树的形态是任意的,肯定是选择一个点作为根,然后其它点和根直接连接最优。为了答案尽量小,又一定是把上面所述距离的最大值作为根。
那么对答案有贡献的就只有三种情况:
1. 原来每棵树的直径
2. 距离最大值+距离次大值+L
3. 距离次大值+距离第3大值+2L
1 #include<cstring> 2 #include<cstdio> 3 #include<algorithm> 4 #include<iostream> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 9 #define N 500007 10 #define M 1000007 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 16 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 int n,m,L; 21 int tot,h[N],e[M],nxt[M],w[M],fa[N],dis[N],D[N],ans,cnt,len[N]; 22 bool v[N]; 23 char c; 24 25 void add(int x,int y,int d) 26 { 27 e[++tot]=y; nxt[tot]=h[x]; w[tot]=d; h[x]=tot; 28 } 29 30 int main() 31 { 32 n=read(); m=read(); L=read(); 33 while (m--) 34 { 35 int x=read()+1,y=read()+1,w=read(); 36 add(x,y,w); add(y,x,w); 37 } 38 for (int i=1;i<=n;i++) 39 if (!v[i]) 40 { 41 D[tot=1]=i; 42 for (int j=1;j<=tot;j++) 43 { 44 int x=D[j]; 45 v[x]=1; 46 for (int k=h[x];k;k=nxt[k]) 47 if (e[k]!=fa[x]) D[++tot]=e[k],dis[e[k]]=dis[x]+w[k],fa[e[k]]=x; 48 } 49 int r=D[tot]; 50 for (int j=1;j<tot;j++) 51 if (dis[D[j]]>dis[r]) r=D[j]; 52 D[tot=1]=r; dis[r]=0; fa[r]=0; 53 for (int j=1;j<=tot;j++) 54 { 55 int x=D[j]; 56 for (int k=h[x];k;k=nxt[k]) 57 if (e[k]!=fa[x]) 58 { 59 D[++tot]=e[k]; 60 dis[e[k]]=dis[x]+w[k]; 61 fa[e[k]]=x; 62 } 63 } 64 r=D[tot]; 65 for (int j=1;j<tot;j++) 66 if (dis[D[j]]>dis[r]) r=D[j]; 67 ans=max(ans,dis[r]); len[++cnt]=dis[r]; 68 for (int j=r;j>0;j=fa[j]) len[cnt]=min(len[cnt],max(dis[j],dis[r]-dis[j])); 69 } 70 sort(len+1,len+cnt+1); 71 if (cnt==2) ans=max(ans,len[2]+len[1]+L); 72 else if (cnt>2) ans=max(ans,max(len[cnt]+len[cnt-1]+L,len[cnt-1]+len[cnt-2]+L*2)); 73 printf("%d\n",ans); 74 }