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

    dp方程很好列:f[i]=min(f[j]+(d[i]-d[j])*p[i]+q[i]),j是i的祖先且d[i]-l[i]<=d[j].

    考虑序列上的做法,这东西显然可以斜率优化,如果j<k且j比k优,则(f[j]-f[k])/(d[j]-d[k])>=p[i].

    但是方程对j的范围有一个限制,所以我们可以考虑分治。

    假设现在正在处理l~mid对mid+1~r的影响。

    我们把mid+1~r按d[i]-l[i]从大到小排序,用l~mid建一个凸包,每次相当于从凸包头插入点,然后询问一个斜率的最优值,二分一下就行了。

    现在这个东西到了树上,我们考虑树的点分治。

    按重心分治,先递归有根的那边,之后把重心子树内的点取出,用根到重心这段的f值去更新,方法同上。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    const int N=200005,M=400005;
    int n,e,si,mx,rt,tp,Tp,fa[N],sz[N],p[N],hd[N],nx[M],to[M],v[N],st[N],St[N];
    ll y,q[N],l[N],w[M],d[N],f[N]; 
    void ad(int x,int y,ll z) {to[++e]=y,w[e]=z,nx[e]=hd[x],hd[x]=e;}
    bool cmp(int x,int y) {return d[x]-l[x]>d[y]-l[y];}
    
    void dfs(int x,int fa) {
        sz[x]=1; int Mx=0;
        for(int i=hd[x];i;i=nx[i]) if(to[i]!=fa&&!v[to[i]]) dfs(to[i],x),sz[x]+=sz[to[i]],Mx=max(Mx,sz[to[i]]);
        Mx=max(Mx,si-sz[x]);
        if(Mx<mx) mx=Mx,rt=x;
    }
    void dfs2(int x,int fa) {sz[x]=1; for(int i=hd[x];i;i=nx[i]) if(to[i]!=fa&&!v[to[i]]) dfs2(to[i],x),sz[x]+=sz[to[i]];}
    void dfs3(int x,int fa) {st[++tp]=x; for(int i=hd[x];i;i=nx[i]) if(to[i]!=fa&&!v[to[i]]) dfs3(to[i],x);}
    
    double xl(int j,int k) {return (double)(f[j]-f[k])/(d[j]-d[k]);}
    void mrg(int y,int x) {
        dfs2(x,0),v[x]=1;
        if(x!=1&&!v[fa[x]]) mx=si=sz[fa[x]],dfs(fa[x],0),mrg(y,rt);
        tp=Tp=0,dfs3(x,fa[x]),sort(st+1,st+1+tp,cmp);
        for(int i=1,u=fa[x];i<=tp;i++) {
            while(u!=fa[y]&&d[st[i]]-l[st[i]]<=d[u]) {
                while(Tp>1&&xl(St[Tp-1],St[Tp])<=xl(St[Tp],u)) Tp--;
                St[++Tp]=u,u=fa[u];
            }
            if(!Tp) continue;
            int l=1,r=Tp;
            while(l<r) {
                int m=(l+r)>>1;
                if(xl(St[m],St[m+1])<p[st[i]]) r=m; else l=m+1;
            }
            f[st[i]]=min(f[st[i]],f[St[l]]+(d[st[i]]-d[St[l]])*p[st[i]]+q[st[i]]);
        }
        for(int i=1;i<=tp;i++) if(st[i]!=x&&d[st[i]]-l[st[i]]<=d[x]) f[st[i]]=min(f[st[i]],f[x]+(d[st[i]]-d[x])*p[st[i]]+q[st[i]]);
        for(int i=hd[x];i;i=nx[i]) if(!v[to[i]]&&to[i]!=fa[x]) mx=si=sz[to[i]],dfs(to[i],0),mrg(to[i],rt);
    }
    
    int main() {
        scanf("%d%*d",&n),memset(f,0x3f,sizeof f),f[1]=0;
        for(int i=2;i<=n;i++) scanf("%d%lld%d%lld%lld",&fa[i],&y,&p[i],&q[i],&l[i]),ad(fa[i],i,y),ad(i,fa[i],y),d[i]=d[fa[i]]+y;
        si=mx=n,dfs(1,0),mrg(1,rt);
        for(int i=2;i<=n;i++) printf("%lld
    ",f[i]);
        return 0;
    }
  • 相关阅读:
    我这些年的项目管理心得...
    14条建议,使你的IT职业生涯更上一层楼
    手机通过WIFI连上ZXV10 H618B路由器但不能上网问题的解决
    优秀中层必备的十大能力
    IMX51启动模式
    VS2005工程由Pocket PC 2003 SDK转为WINCE6.0 SDK的问题
    VS2005工程增加SDK
    VS2005下开发PPC2003和WM50编译器一些设置
    CTO俱乐部下午茶:技术团队管理中的那些事儿
    Android通过JNI调用驱动程序(完全解析实例)
  • 原文地址:https://www.cnblogs.com/juruolty/p/6695022.html
Copyright © 2011-2022 走看看