zoukankan      html  css  js  c++  java
  • [Noi2014]购票

    来自FallDream 的博客,未经允许,请勿转载,谢谢。


    今年夏天,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他们所花的最少资金是多少。
    n<=2*10^5

    dp式子比较容易列出来 f[i]=min f[j]+q[i]+p[i]*(d[i]-d[j)

    考虑斜率优化,发现j比k优,当且仅当p<(f[j]-f[k])/(d[j]-d[k]) 所以考虑维护凸包

    可以直接线段树+无旋treap 大力维护凸包

    也可以cdq分治上树,每次像点分治那样做,然后用包含根的那个子树更新其它子树。

    更新时候按照深度(用于更新的点直接放深度,否则放深度减去limit)排序从下往上做 

    复杂度nlogn^2

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    #define MN 200000
    #define INF 2000000000
    using namespace std;
    inline ll read()
    {
        ll x = 0 , f = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
        while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
     
    ll q[MN+5],p[MN+5],l[MN+5],dep[MN+5],f[MN+5];
    int n,head[MN+5],cnt=0,top,size[MN+5],b[MN+5],fa[MN+5],mx[MN+5],Mx[MN+5];
    struct edge{int to,next;ll w;}e[MN*2+5];
    inline double Getslop(int x,int y){return !y?-INF:(double)(f[y]-f[x])/(dep[y]-dep[x]);}
    struct data{int x,kind;ll dep;}a[MN+5];
    struct CH
    {
        int s[MN+5],tp;
        void clear() {tp=0;}
        void ins(int x)
        {
            while(tp>1&&Getslop(s[tp],s[tp-1])<Getslop(x,s[tp])) --tp;
            s[++tp]=x;
        }   
        int query(ll p)
        {   
            int l=1,r=tp,mid,ans;s[tp+1]=0;
            while(l<=r)
            {
                mid=l+r>>1;
                if(Getslop(s[mid],s[mid+1])<(double)p) ans=mid,r=mid-1;
                else l=mid+1;
            }
            return s[ans];
        }
    }H;
    inline void ins(int f,int t,ll w){e[++cnt]=(edge){t,head[f],w};head[f]=cnt;}
     
    void Pre(int x)
    {
        size[x]=1;mx[x]=0;
        for(int i=head[x];i;i=e[i].next) 
            dep[e[i].to]=dep[x]+e[i].w,Pre(e[i].to),size[x]+=size[e[i].to],mx[x]=max(mx[x],size[e[i].to]);
    }
     
    void GetRt(int x,int tot,int &rt)
    {
        size[x]=1;mx[x]=0;
        for(int i=head[x];i;i=e[i].next)
            if(!b[e[i].to]) GetRt(e[i].to,tot,rt),size[x]+=size[e[i].to],mx[x]=max(mx[x],size[e[i].to]);
        Mx[x]=max(mx[x],tot-size[x]);
        if(size[x]>1&&Mx[x]<Mx[rt]) rt=x;
    }
     
    void Dfs(int x)
    {
        a[++top]=(data){x,0,dep[x]-l[x]};   
        for(int i=head[x];i;i=e[i].next)
            if(!b[e[i].to]) Dfs(e[i].to);
    }
    bool cmp(data x,data y){return x.dep==y.dep?x.kind>y.kind:x.dep>y.dep;}
    ll GetAns(int x,int y){return f[y]+p[x]*(dep[x]-dep[y])+q[x];}
    void Solve(int x,int Sz)
    {
        if(Sz<=1) return;int rt=0;
        GetRt(x,Sz,rt);  
        for(int i=head[rt];i;i=e[i].next) b[e[i].to]=1;
        Solve(x,Sz-size[rt]+1);
        a[top=1]=(data){rt,1,dep[rt]};
        for(int t=fa[rt];t!=fa[x];t=fa[t]) a[++top]=(data){t,1,dep[t]};
        for(int i=head[rt];i;i=e[i].next) Dfs(e[i].to);
        sort(a+1,a+top+1,cmp);H.clear();
        for(int i=1;i<=top;++i)
            if(a[i].kind) H.ins(a[i].x);
            else if(H.tp) f[a[i].x]=min(f[a[i].x],GetAns(a[i].x,H.query(p[a[i].x])));
        for(int i=head[rt];i;i=e[i].next) Solve(e[i].to,size[e[i].to]);
    } 
     
    int main()
    {
        n=read();read();
        memset(f,42,sizeof(f));
        for(int i=2;i<=n;++i)
        {
            fa[i]=read();ll w=read();
            p[i]=read(),q[i]=read();l[i]=read();
            ins(fa[i],i,w); 
        }
        Pre(1);f[1]=0;Mx[0]=INF;Solve(1,size[1]);
        for(int i=2;i<=n;++i) printf("%lld
    ",f[i]);
        return 0;
    }
     
  • 相关阅读:
    防删没什么意思啊,直接写废你~
    绝大多数情况下,没有解决不了的问题,只有因为平时缺少练习而惧怕问题的复杂度,畏惧的心理让我们选择避让,采取并不那么好的方案去解决问题
    Java 模拟面试题
    Crossthread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on
    一步步从数据库备份恢复SharePoint Portal Server 2003
    【转】理解 JavaScript 闭包
    Just For Fun
    The database schema is too old to perform this operation in this SharePoint cluster. Please upgrade the database and...
    Hello World!
    使用filter筛选刚体碰撞
  • 原文地址:https://www.cnblogs.com/FallDream/p/Noi2014d2t3.html
Copyright © 2011-2022 走看看