[长链剖分][线段树] Bzoj P1758 重建计划

Description

Input

第一行包含一个正整数N,表示X国的城市个数. 第二行包含两个正整数L和U,表示政策要求的第一期重建方案中修建道路数的上下限 接下来的N-1行描述重建小组的原有方案,每行三个正整数Ai,Bi,Vi分别表示道路(Ai,Bi),其价值为Vi 其中城市由1..N进行标号

Output

输出最大平均估值,保留三位小数

Sample Input

4
2 3
1 2 1
1 3 2
1 4 3

Sample Output

2.500

HINT

N<=100000,1<=L<=U<=N-1,Vi<=1000000

题解

  • 我们需要处理出每棵子树中每个深度的dis的最大值,就可以用长链剖分+线段树来维护

  • 先递归长儿子,然后继承长儿子的信息,最后合并短儿子的同时顺便维护答案

  • 我们可以先预处理出长链剖分序,也就是在求dfs序的时候先递归长儿子

  • 这样的话必然满足长儿子的子树的大小必然大于该点为根的树的最大深度,这样我们就可以把深度信息用一棵线段树来储存,那么递归完长儿子后该点就可以直接继承长儿子的答案

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 const int N=100010;
 6 const double eps=1e-4,inf=1e15;
 7 int n,L,R,cnt,head[N],deep[N],mx[N],son[N],dfn[N],num[N];
 8 double ans,tmp[N],dis[N];
 9 struct tree{int l,r;double mx;}t[N*5];
10 struct edge{int to,from,w;double v;}e[N*2];
11 void insert(int x,int y,int v)
12 {
13     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt,e[cnt].w=v;
14     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt,e[cnt].w=v;
15 }
16 void dfs1(int x,int fa)
17 {
18     deep[x]=deep[fa]+1,mx[x]=deep[x];
19     for (int i=head[x];i;i=e[i].from)
20         if (e[i].to!=fa) 
21         {
22             dfs1(e[i].to,x),mx[x]=max(mx[x],mx[e[i].to]);
23             if (mx[e[i].to]>mx[son[x]]) son[x]=e[i].to;
24         }
25 }
26 void dfs2(int x,int fa)
27 {
28     dfn[x]=++dfn[0];
29     if (son[x]) dfs2(son[x],x);
30     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa&&e[i].to!=son[x]) dfs2(e[i].to,x);
31 }
32 void build(int d,int l,int r)
33 {
34     t[d].mx=-inf;
35     if (l==r) { num[l]=d; return; }
36     int mid=l+r>>1;
37     build(d*2,l,mid),build(d*2+1,mid+1,r);
38 }
39 void modify(int d,int l,int r,int x,double y)
40 {
41     if (l==r) { t[d].mx=max(t[d].mx,y); return; }
42     int mid=l+r>>1;
43     if (x<=mid) modify(d*2,l,mid,x,y); else modify(d*2+1,mid+1,r,x,y);
44     t[d].mx=max(t[d*2].mx,t[d*2+1].mx);
45 }
46 double query(int d,int l,int r,int x,int y)
47 {
48     if (x>y) return -inf;
49     if (l==x&&r==y) return t[d].mx;
50     int mid=l+r>>1;
51     return max(query(d*2,l,mid,x,min(y,mid)),query(d*2+1,mid+1,r,max(x,mid+1),y));
52 }
53 void dfs(int x,int fa)
54 {
55     modify(1,1,n,dfn[x],dis[x]);
56     for (int i=head[x];i;i=e[i].from) if (e[i].to==son[x]) dis[e[i].to]=dis[x]+e[i].v,dfs(e[i].to,x);
57     for (int i=head[x];i;i=e[i].from)
58         if (e[i].to!=fa&&e[i].to!=son[x])
59         {
60             dis[e[i].to]=dis[x]+e[i].v,dfs(e[i].to,x);
61             for (int j=1;j<=mx[e[i].to]-deep[x];j++)
62             {
63                 tmp[j]=t[num[dfn[e[i].to]+j-1]].mx;
64                 if (j<=R) ans=max(ans,query(1,1,n,max(1,dfn[x]+L-j),min(dfn[x]+mx[x]-deep[x],dfn[x]+R-j))+tmp[j]-2*dis[x]);
65             }
66             for (int j=1;j<=mx[e[i].to]-deep[x];j++) modify(1,1,n,dfn[x]+j,tmp[j]);
67         }
68     ans=max(ans,query(1,1,n,dfn[x]+L,min(dfn[x]+mx[x]-deep[x],dfn[x]+R))-dis[x]);
69 }
70 int main()
71 {
72     scanf("%d%d%d",&n,&L,&R);
73     for (int i=1,x,y,z;i<n;i++) scanf("%d%d%d",&x,&y,&z),insert(x,y,z);
74     dfs1(1,0),dfs2(1,0);
75     double l=0,r=1000000; t[0].mx=-inf;
76     while (r-l>eps)
77     {
78         double mid=(l+r)/2;
79         for (int i=1;i<=cnt;i++) e[i].v=e[i].w-mid;
80         ans=-inf,dis[1]=0,build(1,1,n),dfs(1,0);
81         if (ans<=0) r=mid; else l=mid;
82     }
83     printf("%.3lf",l);
84 }
原文地址:https://www.cnblogs.com/Comfortable/p/11192732.html