zoukankan      html  css  js  c++  java
  • 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("
    ")
     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!='
    ' 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
  • 相关阅读:
    Linux
    CUDA开发
    Linux C++
    Python
    C++
    模式识别
    Linux
    算法
    算法
    leetcode 数组,链表,跳表
  • 原文地址:https://www.cnblogs.com/GhostReach/p/6445848.html
Copyright © 2011-2022 走看看