zoukankan      html  css  js  c++  java
  • [bzoj1767][Ceoi2009]harbingers【dp】

    【题目描述】

    Description

    给定一颗树,树中每个结点有一个邮递员,每个邮递员要沿着唯一的路径走向capital(1号结点),每到一个城市他可以有两种选择: 1.继续走到下个城市 2.让这个城市的邮递员替他出发。 每个邮递员出发需要一个准备时间W[I],他们的速度是V[I],表示走一公里需要多少分钟。 现在要你求出每个城市的邮递员到capital的最少时间(不一定是他自己到capital,可以是别人帮他) N<=100000 3 ≤ N ≤ 100 000 0 ≤ Si≤ 10^9 1 ≤ Vi≤ 10^9 The length of each road will not exceed 10 000 For 20% of the tests, N ≤ 2 500 For 50% of the tests, each town will have at most 2 adjacent roads (i.e., the graph of roads will be a line)

    Input

    N 以下N-1行A,B,C三个数表示A,B之间有一条长为C的边。 再N行每行两数Wi,Vi 输出有一行N-1个数表示如题所述。

    Output

    Sample Input

    5
    1 2 20
    2 3 12
    2 4 1
    4 5 3
    26 9
    1 10
    500 2
    2 30

    Sample Output

    206 321 542 328

    HINT

     

    Source

    【题解】

     树上斜率优化,设dep[j]>dep[k],当前询问的点为i,若j比k优,

    有f[j]+(dep[i]-dep[j])*v[i]+w[i]<f[k]+(dep[i]-dep[j])*v[i]+w[i]

    化简得: f[j]-f[k]<(dep[j]-dep[k])*v[i]

     : (f[j]-f[k])/(dep[j]-dep[k])<v[i]

    单调栈维护斜率的下凸壳即可。

    由于是树。在弹栈时并不是把栈真的弹出,而是在它应该插入的地方打个标记,只改掉这个位置的值,并修改top,

    访问完这个点的子树后,把top和这个点的值都改回来。

     
    /* --------------
        user Vanisher
        problem bzoj-1767 
    ----------------*/
    # include <bits/stdc++.h>
    # define    ll      long long
    # define    N       100010
    using namespace std;
    struct node{
        ll data,next,vote;
    }e[N*2];
    ll stf[N],sdep[N],v[N],w[N],head[N],place,top,f[N],n;
    void build(ll u, ll v, ll d){
        e[++place].data=v; e[place].next=head[u]; head[u]=place; e[place].vote=d;
        e[++place].data=u; e[place].next=head[v]; head[v]=place; e[place].vote=d;
    }
    ll read(){
        ll tmp=0, fh=1; char ch=getchar();
        while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
        while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
        return tmp*fh;
    }
    // f[i]=f[j]+dist(i,j)*v[i]+w[i];
    // f[i]=f[k]+dist(i,k)*v[i]+w[i];
    // f[j]+dist(i,j)*v[i]+w[i]<f[k]+dist(i,k)*v[i]+w[i]
    // f[j]-f[j]<dist(j,k)*v[i]
    // (f[j]-f[k])/dist(j,k)<v[i] // dep[j]>dep[k] 
    ll findin(ll nowf, ll nowd){
        ll l=2, r=top, p=top+1;
        while (l<=r){
            ll mid=(l+r)/2;
            if ((nowf-stf[mid])*1.0/(nowd-sdep[mid])<(stf[mid]-stf[mid-1])*1.0/(sdep[mid]-sdep[mid-1]))
                p=mid, r=mid-1;
                else l=mid+1;
        }
        return p;
    }
    ll query(ll dep, ll v, ll w){
        ll l=2, r=top, p=1;
        while (l<=r){
            ll mid=(l+r)/2;
            if ((stf[mid]-stf[mid-1])*1.0/(sdep[mid]-sdep[mid-1])<v)
                p=mid, l=mid+1;
                else r=mid-1;
        }
        return stf[p]+w+(dep-sdep[p])*v;
    }
    void dfs(ll x, ll fa, ll d){
        ll k=findin(f[x],d);
        ll olddep=sdep[k], oldf=stf[k], oldtop=top;
        sdep[k]=d; stf[k]=f[x]; top=k;
        for (ll ed=head[x]; ed!=0; ed=e[ed].next){
            if (e[ed].data==fa) continue;
            f[e[ed].data]=query(d+e[ed].vote,v[e[ed].data],w[e[ed].data]);
            dfs(e[ed].data,x,d+e[ed].vote);
        }
        sdep[k]=olddep, stf[k]=oldf, top=oldtop;
    }
    int main(){
        n=read();
        for (ll i=1; i<n; i++){
            ll u=read(), v=read(), k=read();
            build(u,v,k);
        }
        for (ll i=2; i<=n; i++)
            w[i]=read(), v[i]=read();
        dfs(1,0,0);
        for (ll i=2; i<n; i++)
            printf("%lld ",f[i]);
        printf("%lld
    ",f[n]);
        return 0;
    }
    


  • 相关阅读:
    优化前台标题,导航,面包屑导航,列表页左侧产品属性,及分类h1标签内文字。
    php Undefined index和Undefined variable的解决方法$_GET
    1 一段很简洁很棒的原生态javascript的Ajax代码
    navicat for mysql 快捷键
    magento 1.6.1.0 安装不上,提示报错:There has been an error processing your request
    libmcrypt.dll
    日志分析软件
    magento本地安装成功后无法进入后台,密码和用户名均正确 .
    禁止所有搜索引擎访问网站的任何部分
    magento安装心得
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136036.html
Copyright © 2011-2022 走看看