BZOJ3246 [Ioi2013]Dreaming
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
正解:树形DP
解题报告:
考场上写的正解,没考虑很多细节,炸到22分。
看了这道题之后感性认识肯定搞出每个连通块内离连通块内所有点中最远距离最小的那个点,有点类似于重心,显然2遍dfs可做。然后就是考虑如何拼接这些连通块。
很容易想到,一定把所有连通块都连在内部距离最大连通块的那个求出来的点上,一定是最优的。但是我们的最远距离计算方式需要谨慎,一般情况下是最大+次大+L,我只考虑了这种就只有22分。事实上最大连通块的直径同样可以成为答案,还有如果L很大的话次大和次次大之间也可构成最长距离,但是注意第三种情况只有是大于等于3个连通块的时候才有可能取到。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 using namespace std; 14 typedef long long LL; 15 #define RG register 16 const int MAXN = 100011; 17 const int MAXM = 200011; 18 const int inf = 2147483647; 19 int n,m,L,ecnt,s; 20 int first[MAXN],to[MAXM],next[MAXM],w[MAXM]; 21 int f[MAXN][2],father[MAXN],son[MAXN],pson[MAXN],belong[MAXN]; 22 int ans1,ans2,ans3,ans; 23 24 inline int getint() 25 { 26 RG int w=0,q=0; RG char c=getchar(); 27 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 28 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 29 } 30 31 inline void dfs(RG int x,RG int fa){ 32 belong[x]=s; RG int now; 33 for(RG int i=first[x];i;i=next[i]) { 34 RG int v=to[i]; if(v==fa) continue; 35 dfs(v,x); now=f[v][0]+w[i]; 36 if(now>f[x][0]) pson[x]=son[x],f[x][1]=f[x][0],f[x][0]=now,son[x]=v; else if(now>f[x][1]) f[x][1]=now,pson[x]=v; 37 } 38 ans=max(f[x][1]+f[x][0],ans); 39 } 40 41 inline void DFS(RG int x,RG int fa,RG int dis){ 42 if(max(f[x][0],dis)<ans) ans=max(f[x][0],dis); 43 for(RG int i=first[x];i;i=next[i]) { 44 RG int v=to[i]; if(v==fa) continue; 45 if(v==son[x]) DFS(v,x,max(dis,f[x][1])+w[i]); 46 else DFS(v,x,max(dis,f[x][0])+w[i]); 47 } 48 } 49 50 inline void work(){ 51 n=getint(); m=getint(); L=getint(); RG int x,y,z; 52 for(RG int i=1;i<=m;i++) { 53 x=getint()+1; y=getint()+1; z=getint(); 54 next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; 55 next[++ecnt]=first[y]; first[y]=ecnt; to[ecnt]=x; w[ecnt]=z; 56 } 57 for(RG int i=1;i<=n;i++) if(!belong[i]) s=i,dfs(i,0); 58 if(m==n-1) { printf("%d",ans); return ; } 59 RG int cun=ans; 60 for(RG int i=1;i<=n;i++) 61 if(belong[i]==i) { 62 ans=inf,DFS(i,0,0); 63 if(ans>ans1) ans3=ans2,ans2=ans1,ans1=ans; 64 else if(ans>ans2) ans3=ans2,ans2=ans; 65 else if(ans>ans3) ans3=ans; 66 } 67 ans=max(cun,ans1+ans2+L); 68 if(m<n-2) ans=max(ans,ans2+ans3+L*2);//必须要多于2块! 69 printf("%d",ans); 70 } 71 72 int main() 73 { 74 work(); 75 return 0; 76 }