BZOJ3672:[NOI2014]购票

Description

今年夏天,NOI在SZ市迎来了她30周岁的生日。来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会。
全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接。为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号。其中SZ市的编号为 1。对于除SZ市之外的任意一个城市 v,我们给出了它在这棵树上的父亲城市 fv  以及到父亲城市道路的长度 sv
从城市 v 前往SZ市的方法为:选择城市 v 的一个祖先 a,支付购票的费用,乘坐交通工具到达 a。再选择城市 a 的一个祖先 b,支付费用并到达 b。以此类推,直至到达SZ市。
对于任意一个城市 v,我们会给出一个交通工具的距离限制 lv。对于城市 v 的祖先 a,只有当它们之间所有道路的总长度不超过 lv  时,从城市 v 才可以通过一次购票到达城市 a,否则不能通过一次购票到达。对于每个城市 v,我们还会给出两个非负整数 pv,qv  作为票价参数。若城市 v 到城市 a 所有道路的总长度为 d,那么从城市 v 到城市 a 购买的票价为 dpv+qv
每个城市的OIer都希望自己到达SZ市时,用于购票的总资金最少。你的任务就是,告诉每个城市的OIer他们所花的最少资金是多少。

Input

第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到)。输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市。其中第 v 行包含 5 个非负整数 f_v,s_v,p_v,q_v,l_v,分别表示城市 v 的父亲城市,它到父亲城市道路的长度,票价的两个参数和距离限制。请注意:输入不包含编号为 1 的SZ市,第 2 行到第 n 行分别描述的是城市 2 到城市 n。

Output

输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。

Sample Input

7 3
1 2 20 0 3
1 5 10 100 5
2 4 10 10 10
2 9 1 100 10
3 5 20 100 10
4 4 20 0 10

Sample Output

40
150
70
149
300
150

HINT

对于所有测试数据,保证 0≤pv≤106,0≤qv≤1012,1≤fv<v;保证 0<sv≤lv≤2×1011,且任意城市到SZ市的总路程长度不超过 2×1011

输入的 t 表示数据类型,0≤t<4,其中:

当 t=0 或 2 时,对输入的所有城市 v,都有 fv=v-1,即所有城市构成一个以SZ市为终点的链;

当 t=0 或 1 时,对输入的所有城市 v,都有 lv=2×1011,即没有移动的距离限制,每个城市都能到达它的所有祖先;

当 t=3 时,数据没有特殊性质。

n=2×10^5

 

题解:

比较容易地看出这是一道dp题,而且和斜率优化有一些关系。

用dep表示到根的距离,则dp方程ans[i]<——ans[j]+p[i]*(dep[i]-dep[j])+q[i](j是i可以到达的点)。

若跳到k比跳到j优(dep[k]>dep[j]),即ans[j]-p[i]*dep[j]>ans[k]-p[i]*dep[k]  ——>  p[i]>(ans[k]-ans[j])/(dep[k]-dep[j])

这个式子很像斜率优化,但因为有l[i]的限制,不能只维护一个下凸壳。

考虑一条链的情况,可以采用CDQ分治:

设lim[i]=dep[i]-l[i],求出左半边的答案,将右边的点按照lim排序。

维护左半边的下凸壳,在这个下凸壳上二分更新右边元素的答案。从右往左把左边元素加到下凸壳中,按排序的顺序依次根据当前下凸壳更新答案。

到了树上,也可以采用这种方法:先求解最浅分治子块,设目前分治块中根为root,最浅点为less,将其他分治子块排序,依次加入root~less维护下凸壳。

也就是有根树的CDQ分治。

 

代码(P++注意):

  1 #include<bits/stdc++.h>
  2 #define begin {
  3 #define end }
  4 #define while while(
  5 #define if if(
  6 #define do )
  7 #define then )
  8 #define for for(
  9 #define fillchar(a,b,c) memset(a,c,b)
 10 #define writeln printf("\n")
 11 #define write printf
 12 #define readln readl()
 13 #define inc(a) a++
 14 #define dec(a) a--
 15 #define exit(a) return a
 16 #define mod %
 17 #define div /
 18 #define shl <<
 19 #define shr >>
 20 #define extended long double
 21 #define longint int
 22 #define integer short
 23 #define int64 long long
 24 using namespace std;
 25 template<typename T> inline void read(T& a)
 26 begin
 27   T x=0,f=1; char ch=getchar();
 28   while(ch<'0')or(ch>'9')do
 29   begin
 30     if ch=='-' then f=-1; ch=getchar();
 31   end
 32   while(ch>='0')and(ch<='9')do
 33   begin
 34     x=x*10+ch-'0'; ch=getchar();
 35   end
 36   a=x*f;
 37 end
 38 inline void readl()
 39 begin
 40   char ch; ch=getchar();
 41   while ch!='\n' do ch=getchar();
 42 end
 43 int64 s[300000],p[300000],q[300000],l[300000],n,m,i,j,dep[300000],ans[300000];
 44 int64 vis[300000],siz[300000],c[300000],last[300000],mx[300000],root,size,lb[300000],lb2[300000],cnt,cnt2,f[300000];
 45 bool xiaoyu(int64 a,int64 b)
 46 begin
 47   exit(dep[a]-l[a]>dep[b]-l[b]);
 48 end
 49 void dfs(int64 x,int64 fa)
 50 begin
 51   siz[x]=1; mx[x]=0;
 52   if(vis[f[x]]==0)and(f[x]!=fa)then
 53   begin dfs(f[x],x); siz[x]=siz[x]+siz[f[x]]; mx[x]=max(mx[x],siz[f[x]]); end
 54   for int64 i=c[x];i;i=last[i] do
 55   if(vis[i]==0)and(i!=fa)then
 56   begin dfs(i,x); siz[x]=siz[x]+siz[i]; mx[x]=max(mx[x],siz[i]); end
 57   mx[x]=max(mx[x],size-siz[x]); if mx[x]<mx[root] then root=x;
 58 end
 59 void getdep(int64 x,int64 fa)
 60 begin
 61   dep[x]=dep[fa]+s[x];
 62   for int64 i=c[x];i;i=last[i] do getdep(i,x);
 63 end
 64 void getsiz(int64 x,int64 fa)
 65 begin
 66   siz[x]=1;
 67   if(f[x]!=fa)and(vis[f[x]]==0)then begin getsiz(f[x],x); siz[x]=siz[x]+siz[f[x]]; end
 68   for int64 i=c[x];i;i=last[i] do 
 69   if(i!=fa)and(vis[i]==0)then begin getsiz(i,x); siz[x]=siz[x]+siz[i]; end
 70 end
 71 void dfs2(int64 x,int64 fa)
 72 begin
 73   inc(cnt); lb[cnt]=x;
 74   if(f[x]!=fa)and(vis[f[x]]==0)then dfs2(f[x],x);
 75   for int64 i=c[x];i;i=last[i] do 
 76   if(i!=fa)and(vis[i]==0)then dfs2(i,x);
 77 end
 78 int64 ef(int64 xl)
 79 begin
 80   int64 anss=1,l=2,r=cnt2,mid;
 81   while l<=r do
 82   begin
 83     mid=(l+r)div 2;
 84     long double xl1=ans[lb2[mid]]-ans[lb2[mid-1]];
 85     xl1=xl1/(dep[lb2[mid]]-dep[lb2[mid-1]]);
 86     if xl1>=xl then begin anss=mid; l=mid+1; end else r=mid-1;
 87   end;
 88   exit(anss);
 89 end
 90 int64 work(int64 x,int dp)
 91 begin
 92   vis[x]=1; int64 less=dep[x];
 93   if vis[f[x]]==0 then getsiz(f[x],x);
 94   for int64 i=c[x];i;i=last[i] do
 95   if vis[i]==0 then getsiz(i,x);
 96   if vis[f[x]]==0 then
 97   begin 
 98     size=siz[f[x]]; root=0; dfs(f[x],x); less=min(work(root,dp+1),less);
 99     cnt2=0; j=f[x];
100     while(dep[j]>=less)and(dep[x]-l[x]<=dep[j])do
101     begin
102       while cnt2>1 do
103       begin
104         long double xl1=ans[lb2[cnt2]]-ans[lb2[cnt2-1]],xl2=ans[j]-ans[lb2[cnt2]];
105         xl1=xl1/(dep[lb2[cnt2]]-dep[lb2[cnt2-1]]); xl2=xl2/(dep[j]-dep[lb2[cnt2]]);
106         if xl1<=xl2 then dec(cnt2);else break;
107       end
108       inc(cnt2); lb2[cnt2]=j; j=f[j];
109     end
110     if cnt2>0 then
111     begin
112       int64 y=lb2[ef(p[x])]; 
113       ans[x]=min(ans[x],ans[y]+(dep[x]-dep[y])*p[x]+q[x]);
114     end
115   end
116   cnt=0;
117   for int64 i=c[x];i;i=last[i] do
118   if vis[i]==0 then dfs2(i,x);
119   sort(lb+1,lb+cnt+1,xiaoyu); cnt2=0; j=x;
120   for int64 i=1;i<=cnt;i++ do
121   begin
122     while(dep[j]>=less)and(dep[lb[i]]-l[lb[i]]<=dep[j])do
123     begin
124       while cnt2>1 do
125       begin
126         long double xl1=ans[lb2[cnt2]]-ans[lb2[cnt2-1]],xl2=ans[j]-ans[lb2[cnt2]];
127         xl1=xl1/(dep[lb2[cnt2]]-dep[lb2[cnt2-1]]); xl2=xl2/(dep[j]-dep[lb2[cnt2]]);
128         if xl1<=xl2 then dec(cnt2);else break;
129       end
130       inc(cnt2); lb2[cnt2]=j; j=f[j];
131     end
132     if cnt2>0 then
133     begin
134       int64 y=lb2[ef(p[lb[i]])]; 
135       ans[lb[i]]=min(ans[lb[i]],ans[y]+(dep[lb[i]]-dep[y])*p[lb[i]]+q[lb[i]]);
136     end
137   end
138   for int64 i=c[x];i;i=last[i] do
139   if vis[i]==0 then
140   begin size=siz[i]; root=0; dfs(i,x); work(root,dp+1); end
141   exit(less);
142 end      
143 int main()
144 begin
145   read(n); int64 t; read(t);
146   for i=2;i<=n;i++ do
147   begin
148     read(f[i]); read(s[i]); read(p[i]); read(q[i]); read(l[i]);
149     last[i]=c[f[i]]; c[f[i]]=i; ans[i]=999999999999999999;
150   end
151   getdep(1,0); dep[0]=-1;
152   vis[0]=1; root=0; mx[0]=n; size=n; dfs(1,0);
153   work(root,0);
154   for int64 i=2;i<=n;i++ do begin write("%lld",ans[i]); writeln; end
155 end
View Code
posted @ 2017-02-26 21:01  GhoStreach  阅读(218)  评论(0编辑  收藏  举报