CS academy Growing Trees【模板】DP求树的直径
标签:pac code mem inline long png nbsp namespace mes
【题意概述】
给出一棵树,树上的边有两个值a和b,你可以在[0,limit]范围内选择一个整数delta,树上的边的权值为a+b*delta,现在问当delta为多少的时候树的直径最小、最小直径是多少。
【题解】
每条边的边权都是一次函数,那么直径是单峰函数。单峰函数求最小值我们可以用三分法。
注意边权可能为负数,求直径时要用DP,而不能用dfs到最远点、再从最远点dfs到它的最远点的方法。
1 #include 2 #include 3 #include
4 #define LL long long
5 #define rg register
6 #define N 500010
7 using namespace std;
8 int n,m,tot,del,l,r,last[N];
9 LL ans=3e18,mx,dis[N][2];
10 struct edge{
11 int to,pre; LL w;
12 }e[N1];
13 struct rec{
14 int u,v,a,b;
15 }re[N];
16 inline int read(){
17 int k=0,f=1; char c=getchar();
18 while(c‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar();
19 while(‘0‘‘9‘)k=k*10+c-‘0‘,c=getchar();
20 return k*f;
21 }
22 void dfs(int x,int fa){
23 for(rg int i=last[x],to;i;i=e[i].pre)if((to=e[i].to)!=fa){
24 dfs(to,x); LL tmp=dis[to][0]+e[i].w;
25 if(tmp>=dis[x][0]){
26 dis[x][1]=dis[x][0],dis[x][0]=tmp;
27 }
28 else
29 if(tmp>dis[x][1]) dis[x][1]=tmp;
30 }
31 mx=max(mx,max(dis[x][0],dis[x][0]+dis[x][1]));
32 }
33 inline LL calc(int x){
34 memset(last,0,sizeof(last)); tot=0;
35 for(rg int i=1;i){
36 int u=re[i].u,v=re[i].v; LL w=re[i].a+re[i].b*x;
37 e[++tot]=(edge){u,last[v],w}; last[v]=tot;
38 e[++tot]=(edge){v,last[u],w}; last[u]=tot;
39 }
40 memset(dis,0,sizeof(dis)); mx=0;
41 dfs(1,0);
42 return mx;
43 }
44 signed main(){
45 n=read(); l=-1; r=read();
46 for(rg int i=1;i){
47 re[i].u=read(); re[i].v=read(); re[i].a=read(); re[i].b=read();
48 }
49 while(l+1r){
50 int mid1=(l+r)>>1,mid2=mid1+1;
51 if(calc(mid1)mid1;
52 else l=mid1;
53 }
54 printf("%d\n%lld\n",r,calc(r));
55 return 0;
56 }
CS academy Growing Trees【模板】DP求树的直径
标签:pac code mem inline long png nbsp namespace mes
原文地址:https://www.cnblogs.com/DriverLao/p/9883009.html
评论