标签:bzoj 题解 ioi 树形dp
【原题】
3246: [Ioi2013]Dreaming
Time Limit: 10 Sec Memory Limit: 64 MB
Submit: 194 Solved: 68
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
12 8 2
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
18
【分析】话说此题坑了我一上午。许昊然的题解已经讲得很详细了。
http://www.ccf.org.cn/resources/1190201776262/fujian/xuhaoran2013-07-25-03_33_55.pdf
但是我还想补充几点:
①设树中一个点到其他点的最长距离为S,怎么快速求一棵树的S的最大值(即直径)和最小值。
对于某个点i,我们设max[i]表示它的最远儿子距离他的长度。再定义maxx[i]表示不经过它的max[i]经过的儿子的最远距离(也就是次远距离)。我们可以先做一遍树规,把这两个值预处理一下。
然后我们考虑第二遍DP时,如何线性求出每个i点到其他点的最长距离。
显然,根节点的S=max[root]。我们用G[i]表示从i的父亲结点及以上转移过来的最长长度。显然,对于结点i,S=max(max[i],G[i])然后再考虑G[i]的转移。如果i是父亲max[fa]经过的路径,G[i]=max(maxx[fa],G[i]),否则G[I]=max(max[fa],G[i])。随便YY即可。
②我们不妨设每棵树求出来的S的最大值是D[i],最小值是E[i]。显然,我们应该摆成以上形式,使得E[i]最大的在上面。我们再设底下的的E[I]是降序排序的,分别标为E[1],E[2],E[3]。。。那么ans=max(max1+max2+L,max2+max3+2*L)。
③细节很坑。我们要把ans与每一个D[i]求max。别忘了再特判只有1个或2个的情况。
【代码】
#include<cstdio>
#include<algorithm>
#define N 500005
using namespace std;
struct arr{int go,next,s;}a[N*2];
int f[N],Max[N],Maxx[N],temp[N],D[N],E[N],end[N],G[N];
int num,p,i,x,y,z,n,m,L,ans,cnt,Cnt,max1,max2,max3;
void add(int u,int v,int w)
{
a[++cnt].go=v;a[cnt].next=end[u];a[cnt].s=w;end[u]=cnt;
}
int get(int u){return (f[u]==u)?u:f[u]=get(f[u]);}
void Union(int u,int v)
{
int uu=get(u),vv=get(v);
if (uu==vv) return;f[vv]=uu;
}
void Get(int k,int fa)
{
for (int i=end[k];i;i=a[i].next)
{
int go=a[i].go;if (go==fa) continue;
Get(go,k);
if (Max[go]+a[i].s>Max[k]) Max[k]=Max[go]+a[i].s,temp[k]=go;
}
for (int i=end[k];i;i=a[i].next)
{
int go=a[i].go;
if (go!=fa&&Max[go]+a[i].s>Maxx[k]&&temp[k]!=go) Maxx[k]=Max[go]+a[i].s;
}
}
void Dfs(int k,int fa)
{
for (int i=end[k];i;i=a[i].next)
{
int go=a[i].go;if (go==fa) continue;
G[go]=max(G[k],(temp[k]==go)?Maxx[k]:Max[k])+a[i].s;
int now=max(Max[go],G[go]);
if (now>D[p]) D[p]=now;
if (now<E[p]) E[p]=now;
Dfs(go,k);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&L);
for (i=1;i<=n;i++) f[i]=i;
for (i=1;i<=m;i++)
scanf("%d%d%d",&x,&y,&z),add(++x,++y,z),add(y,x,z),Union(x,y);
for (p=1;p<=n;p++)
if (f[p]==p)
{
Get(p,0);G[p]=0;D[p]=E[p]=Max[p];
Dfs(p,0);ans=max(ans,D[p]);
if (E[p]>max1) {max3=max2;max2=max1;max1=E[p];}
else if (E[p]>max2) {max3=max2;max2=E[p];}
else if (E[p]>max3) max3=E[p];
Cnt++;
}
if (Cnt>1) ans=max(ans,max1+max2+L);
if (Cnt>2) ans=max(ans,max2+max3+2*L);
printf("%d",ans);
return 0;
}
bzoj 3246 [Ioi2013] Dreaming 题解,布布扣,bubuko.com
bzoj 3246 [Ioi2013] Dreaming 题解
标签:bzoj 题解 ioi 树形dp
原文地址:http://blog.csdn.net/jiangshibiao/article/details/26331215