bzoj3672【NOI2014】购票
题目描述
今年夏天,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他们所花的最少资金是多少。
输入格式
第 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。
输出格式
输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。
数据规模
-
题解:
- 设$v$是$u$的祖先,$dp[u] = dp[v] + (dis[u]-dis[v])*p[u] + q[u] \ , \ (dis[u]-dis[v]<=l[u])$
- 斜率优化部分:
- 假设$d[v_{1}]<d[v_{2}]$且对$u$来说$v2$比$v1$更优:
- $$dp[v_{1}]+(dis[u]-dis[v_{1}])*p[u]+q[u] > dp[v_{2}]+(dis[u]-dis[v_{2}])*p[u]+q[u] ;$$
- $$\frac{dp[v_{2}]-dp[v_{1}]}{dis[v2]-dis[v1]} < p[u]$$
- 可以维护$(dis[v],dp[v])$的下凸包(斜率单调上升);
- 由于是在一颗树上且有$l$的限制,所以我们需要用用一些方法维护一下,
- 可以找树的重心分治,我写的树剖:
- 对每个重链的顶端维护一个凸包,$dfs$的时候不断加入点;
- 我们先$dfs$轻儿子,这样一个点到根的轻链的父亲都是一个凸包的末端;
- 找转移点的时候不断向上跳,如果某条链全部满足限制则在重链顶端的凸包上直接查询;
- 否则一定是合法的分界点在当前找到的链上,用线段树维护区间的凸包查询即可;
- 一次最多找到$log$条树链,最多有一条树链需要在线段树里面查询;
- 算上三分,时间复杂度:$O(nlog^2n)$
- 有个小技巧,线段树满了之后再做凸包
1 #include<bits/stdc++.h> 2 #define ls (k<<1) 3 #define rs (k<<1|1) 4 #define ll long long 5 #define ld double 6 using namespace std; 7 const int N=200010; 8 char gc(){ 9 static char*p1,*p2,s[1000000]; 10 if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin); 11 return(p1==p2)?EOF:*p1++; 12 } 13 ll rd(){ 14 ll x=0; char c=gc(); 15 while(c<'0'||c>'9')c=gc(); 16 while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc(); 17 return x; 18 } 19 int n,T,f[N],o=1,hd[N],dep[N],fa[N][20],bin[20]; 20 int idx,sz[N],tp[N],sn[N],mx[N],id[N],cnt[N<<2],st[N]; 21 ll dp[N],tmp,dis[N],s[N],p[N],q[N],l[N]; 22 struct Poi{ 23 ld x,y; 24 Poi(ld _x=0,ld _y=0):x(_x),y(_y){}; 25 Poi operator -(const Poi&a){return Poi(x-a.x,y-a.y);} 26 ld operator ^(const Poi&a){return x*a.y-y*a.x;} 27 bool operator <(const Poi&a){return x==a.x?y<a.y:x<a.x;} 28 }P[N]; 29 vector<int>g1[N<<2],g2[N]; 30 struct Edge{int v,nt;}E[N]; 31 void adde(int u,int v){E[o]=(Edge){v,hd[u]};hd[u]=o++;} 32 void dfs1(int u){ 33 sz[u]=1; 34 fa[u][0]=f[u]; 35 dep[u]=dep[f[u]]+1; 36 dis[u]=dis[f[u]]+s[u]; 37 for(int i=1;bin[i]<dep[u];++i)fa[u][i]=fa[fa[u][i-1]][i-1]; 38 for(int i=hd[u];i;i=E[i].nt){ 39 int v=E[i].v; 40 dfs1(v); 41 sz[u]+=sz[v]; 42 if(sz[v]>sz[sn[u]])sn[u]=v; 43 } 44 } 45 void dfs2(int u,int t){ 46 tp[u]=t; 47 id[u]=++idx; 48 st[idx]=u; 49 if(sn[u])dfs2(sn[u],t); 50 for(int i=hd[u];i;i=E[i].nt){ 51 int v=E[i].v; 52 if(v==sn[u])continue; 53 dfs2(v,v); 54 } 55 } 56 inline bool judge(int a,int b,int c){return ((P[b]-P[a])^(P[c]-P[b]))<=0;} 57 void pushup(int k){ 58 int l=ls,r=rs,tl=0,tr=0; 59 while(tl<(int)g1[l].size()||tr<(int)g1[r].size()){ 60 if(tr==(int)g1[r].size()||(tl<(int)g1[l].size()&&g1[l][tl]<g1[r][tr])){ 61 while(g1[k].size()>1&&judge(g1[k][g1[k].size()-2],g1[k].back(),g1[l][tl]))g1[k].pop_back(); 62 g1[k].push_back(g1[l][tl++]); 63 }else{ 64 while(g1[k].size()>1&&judge(g1[k][g1[k].size()-2],g1[k].back(),g1[r][tr]))g1[k].pop_back(); 65 g1[k].push_back(g1[r][tr++]); 66 } 67 } 68 } 69 void ins1(int k,int l,int r,int u){ 70 cnt[k]++; 71 if(l==r){g1[k].push_back(u);return;} 72 int mid=(l+r)>>1; 73 if(id[u]<=mid)ins1(ls,l,mid,u); 74 else ins1(rs,mid+1,r,u); 75 if(tp[st[l]]==tp[st[r]]&&cnt[k]==r-l+1)pushup(k); 76 } 77 void ins2(int k,int u){ 78 while(g2[k].size()>1&&judge(g2[k][g2[k].size()-2],g2[k].back(),u))g2[k].pop_back(); 79 g2[k].push_back(u); 80 } 81 inline bool ok(int u,int v){return dis[u]-dis[v]<=l[u];} 82 inline void upd(ll&x,ll y){if(x>y)x=y;} 83 void cal(vector<int>&g,int u){ 84 int l=0,r=g.size()-1; 85 while(r-l>2){ 86 int mid=(r-l)/3,mid1=l+mid,mid2=r-mid; 87 ll t1=dp[g[mid1]]-dis[g[mid1]]*p[u]; 88 ll t2=dp[g[mid2]]-dis[g[mid2]]*p[u]; 89 if(t1>t2)l=mid1+1; 90 else r=mid2-1; 91 } 92 for(int i=l;i<=r;++i)upd(tmp,dp[g[i]]-dis[g[i]]*p[u]); 93 } 94 void query1(int k,int l,int r,int x,int y,int u){ 95 if(l==x&&r==y){cal(g1[k],u);return;} 96 int mid=(l+r)>>1; 97 if(y<=mid)query1(ls,l,mid,x,y,u); 98 else if(x>mid)query1(rs,mid+1,r,x,y,u); 99 else query1(ls,l,mid,x,mid,u),query1(rs,mid+1,r,mid+1,y,u); 100 } 101 void query2(int x,int u){ 102 cal(g2[x],u); 103 } 104 void solve(int u){ 105 tmp=u==1?0:9e18; 106 for(int x=f[u],t=tp[x];x;x=f[t],t=tp[x]){ 107 if(dep[mx[u]]<dep[t])query2(id[t],u); 108 else {query1(1,1,n,id[mx[u]],id[x],u);break;} 109 } 110 dp[u]=dis[u]*p[u]+q[u]+tmp; 111 P[u]=Poi(dis[u],dp[u]); 112 ins1(1,1,n,u); 113 ins2(id[tp[u]],u); 114 } 115 void calmx(int u){ 116 int t=u; 117 for(int i=17;~i;--i)if(fa[t][i]&&ok(u,fa[t][i]))t=fa[t][i]; 118 mx[u]=t; 119 } 120 void dfs3(int u){ 121 calmx(u); 122 solve(u); 123 for(int i=hd[u];i;i=E[i].nt){ 124 int v=E[i].v; 125 if(v==sn[u])continue; 126 dfs3(v); 127 } 128 if(sn[u])dfs3(sn[u]); 129 } 130 int main(){ 131 #ifndef ONLINE_JUDGE 132 freopen("bzoj3672.in","r",stdin); 133 freopen("bzoj3672.out","w",stdout); 134 #endif 135 for(int i=bin[0]=1;i<=18;++i)bin[i]=bin[i-1]<<1; 136 n=rd();T=rd(); 137 for(int i=2;i<=n;++i){ 138 adde(f[i]=rd(),i); 139 s[i]=rd();p[i]=rd(); 140 q[i]=rd();l[i]=rd(); 141 } 142 dfs1(1); 143 dfs2(1,1); 144 dfs3(1); 145 for(int i=2;i<=n;++i)printf("%lld\n",dp[i]); 146 return 0; 147 }