购票

来源:互联网 发布:首都图书馆 知乎 编辑:程序博客网 时间:2024/04/29 07:35

购票

题目放个传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3672

题解

很容易推出暴力dp:f[i]=f[j]+p[i]*(dep[i]-dep[j])+q[i]。
我们可以设k=dep[j],b=f[j],x=p[i],如果是链斜率优化即可。不是链的话,每次把每个节点到根的路径取出来处理即可。
正解:点分治+cdq分治。(本蒟蒻太懒(弱)了不想(会)写。)
本蒟蒻写的暴力:树链剖分,对于每个线段树结点建立一个凸包,每次查询操作在凸包上二分斜率即可。复杂度O(n*log(n)^3),看起来很吓人对吧,然而仔细一看不难发现常数极小,可以轻松水过。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<cmath>#include<vector>#include<algorithm>#define ll long long#define inf 99999999999999999ll#define N 200010using namespace std;int n,fa[N],p[N];int size[N],top[N],next[N],flag[N];int st[N],end[N],pos[N],num[N],pl[N],tot,rt[N];int la[N],ff[N],Q[N],s[N*18],tmp,cnt;ll f[N],len[N],q[N],dis[N];struct node{int a,b;ll c;}map[N];struct point{  int lc,rc,fa,l,sum;  double cal(int x,int y)  {    return double(f[x]-f[y])/(dis[x]-dis[y]);  }  void insert(int x)  {    if(sum<2){s[l+sum]=x,sum++;return;}    while(sum-1&&cal(s[l+sum-2],s[l+sum-1])>=cal(s[l+sum-2],x))sum--;    s[l+sum]=x;sum++;  }  ll qry(int x)  {    int lx=l,rx=l+sum-1;    while(rx-lx>1)    {      int mid=lx+rx>>1;      if(cal(s[mid],s[mid+1])>p[x])rx=mid;      else lx=mid+1;    }    return min(f[s[lx]]-p[x]*dis[s[lx]],f[s[rx]]-p[x]*dis[s[rx]]);  }}t[N*4];class seg_tree{  vector<pair<ll,int> >tp;  ll qry(int x,int l,int r,int ql,int qr,int k)  {    if(ql<=l&&r<=qr){return t[x].qry(k);}    int lc=t[x].lc,rc=t[x].rc,mid=l+r>>1;    ll res=inf;    if(ql<=mid)res=min(res,qry(lc,l,mid,ql,qr,k));    if(qr>mid)res=min(res,qry(rc,mid+1,r,ql,qr,k));    return res;  }  public:  void build(int x,int l,int r)  {    t[x].l=tmp+1;t[x].sum=0;tmp+=r-l+1;    if(l==r){pl[num[l]]=x;return;}    int mid=l+r>>1;    build(t[x].lc=++cnt,l,mid);    build(t[x].rc=++cnt,mid+1,r);    t[t[x].lc].fa=x;t[t[x].rc].fa=x;  }  ll query(int x,int ql,int qr,int k)  {    if(tp.empty()||dis[k]-len[k]>dis[num[qr]])return inf;    if(dis[k]-len[k]<=dis[num[ql]])return qry(rt[x],st[x],end[x],ql,qr,k);    int pp=lower_bound(tp.begin()+ql-1,tp.begin()+qr-1,make_pair(dis[k]-len[k],0))->second;    return qry(rt[x],st[x],end[x],max(pp,ql),qr,k);  }  void insert(int x)  {    for(int p=pl[x];p;p=t[p].fa)t[p].insert(x);    tp.push_back(make_pair(dis[x],pos[x]));  }}T[N];void bfs(){  int l=1,r=2;Q[1]=1;  while(l<r)  {    int x=Q[l];size[x]=1;l++;    for(int a=la[x];a;a=ff[a])      Q[r]=map[a].b,dis[Q[r]]=dis[x]+map[a].c,r++;  }  for(int i=r-1;i;i--)  {    int x=Q[i];size[fa[x]]+=size[x];    if(size[next[fa[x]]]<size[x])next[fa[x]]=x;  }  for(int i=1;i<r;i++)  {    int x=Q[i];    if(flag[x])continue;st[x]=tot+1;    for(int j=x;j;j=next[j])      pos[j]=++tot,num[tot]=j,top[j]=x,flag[j]=1;    end[x]=tot;    T[x].build(rt[x]=++cnt,st[x],end[x]);  }}int main(){  int a;ll c;  scanf("%d%d",&n,&a);  for(int i=2;i<=n;i++)  {    scanf("%d%lld%d%lld%lld",&a,&c,&p[i],&q[i],&len[i]);    map[i]=(node){a,i,c};ff[i]=la[a];la[a]=i;fa[i]=a;  }  bfs();T[1].insert(1);  for(int i=2;i<=n;i++)  {    int v=Q[i],x,y;    f[v]=T[top[v]].query(top[v],st[top[v]],pos[v]-1,v);    x=fa[top[v]];y=top[x];    for(;x;x=fa[y],y=top[x])      f[v]=min(f[v],T[y].query(y,st[y],pos[x],v));    f[v]+=(ll)p[v]*dis[v]+q[v];T[top[v]].insert(v);  }  for(int i=2;i<=n;i++)printf("%lld\n",f[i]);  return 0;}
0 0