[bzoj1767][Ceoi2009]harbingers (树上斜率优化)
给定一颗树,树中每个结点有一个邮递员,每个邮递员要沿着唯一的路径走向capital(1号结点),每到一个城市他可以有两种选择: 1.继续走到下个城市 2.让这个城市的邮递员替他出发。 每个邮递员出发需要一个准备时间W[I],他们的速度是V[I],表示走一公里需要多少分钟。 现在要你求出每个城市的邮递员到capital的最少时间(不一定是他自己到capital,可以是别人帮他) N<=100000 3 ≤ N ≤ 100 000 0 ≤ Si≤ 10^9 1 ≤ Vi≤ 10^9 The length of each road will not exceed 10 000 For 20% of the tests, N ≤ 2 500 For 50% of the tests, each town will have at most 2 adjacent roads (i.e., the graph of roads will be a line)
Input
N 以下N-1行A,B,C三个数表示A,B之间有一条长为C的边。 再N行每行两数Wi,Vi 输出有一行N-1个数表示如题所述。
Output
Sample Input
5
1 2 20
2 3 12
2 4 1
4 5 3
26 9
1 10
500 2
2 30
Sample Output
206 321 542 328
solution:
树上斜率优化,设dep[j]>dep[k],当前询问的点为i,若j比k优,
有f[j]+(dep[i]-dep[j])*v[i]+w[i]<f[k]+(dep[i]-dep[j])*v[i]+w[i]
化简得: f[j]-f[k]<(dep[j]-dep[k])*v[i]
即 : (f[j]-f[k])/(dep[j]-dep[k])<v[i]
单调栈维护斜率的下凸壳即可。
由于是树。在弹栈时并不是把栈真的弹出,而是在它应该插入的地方打个标记,只改掉这个位置的值,并修改top,
访问完这个点的子树后,把top和这个点的值都改回来。
CODE:
1 # include <iostream>
2 # include <cstdio>
3 # include <cstring>
4 using namespace std;
5 const int N = 3e5 + 12;
6 typedef long long LL;
7 int n,dt,head[N],que[N];
8 LL f[N],d[N],v[N],w[N];
9 struct Edge
10 {
11 int to,nex;
12 LL w;
13 } edge[N << 1];
14 void AddEdge(int u,int v,LL w)
15 {
16 edge[++dt] = (Edge)
17 {
18 v,head[u],w
19 };
20 head[u] = dt;
21 }
22 LL x(int i)
23 {
24 return d[i];
25 }
26 LL y(int i)
27 {
28 return f[i];
29 }
30 LL Get(int A,int B)
31 {
32 return f[A] + (d[B] - d[A]) * v[B] + w[B];
33 }
34 double slope(int A,int B)
35 {
36 return ((double)(y(B) - y(A))) / ((double)(x(B) - x(A)));
37 }
38 bool Cross(int A,int B,int C)
39 {
40 return slope(B,C) <= slope(A,B);
41 }
42 int find(int x,int tp)
43 {
44 int l=1,r=tp-1,ret=tp,mid;
45 // 注意ret初始值
46 while(l <= r)
47 {
48 mid = l + r >> 1;
49 if(slope(que[mid],que[mid+1]) > (double)v[x]) ret=mid,r=mid-1;
50 else l = mid + 1;
51 }
52 return ret;
53 }
54
55 int Find(int z,int tp)
56 {
57 int l=0,r=tp-1,ret=tp+1;
58 // 注意ret初始值
59 while(l<=r)
60 {
61 int mid =l+r>>1;
62 if(slope(que[mid],z)<=slope(que[mid],que[mid+1]))ret=mid+1,r=mid-1;
63 else l=mid+1;
64 }
65 return ret;
66 }
67
68 void dfs(int u,int pos,int fa)
69 {
70 int qpos,qtop;
71 f[u] = Get(que[find(u,pos)],u);
72 qpos = Find(u,pos);
73 qtop = que[qpos];
74 que[qpos] = u;
75 for(int i = head[u]; i; i = edge[i].nex)
76 {
77 if(edge[i].to == fa)continue;
78 d[edge[i].to] = d[u] + edge[i].w;
79 dfs(edge[i].to,qpos,u);
80 }
81 que[qpos] = qtop;
82 }
83 int main()
84 {
85 scanf("%d",&n);
86 int x,y,z;
87 for(int i = 1; i < n; i++)
88 {
89 scanf("%d %d %d",&x,&y,&z);
90 AddEdge(x,y,z);
91 AddEdge(y,x,z);
92 }
93 for(int i = 2; i <= n; i++)scanf("%lld %lld",&w[i],&v[i]);
94 dfs(1,0,0);
95 printf("%lld",f[2]);
96 for(int i = 3; i <= n; i++)printf(" %lld",f[i]);
97 }