BZOJ3672:[NOI2014]购票
Description
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
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
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++注意):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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