zoukankan      html  css  js  c++  java
  • [bzoj1767][Ceoi2009]harbingers (树上斜率优化)


    给定一颗树,树中每个结点有一个邮递员,每个邮递员要沿着唯一的路径走向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


    solution:

     树上斜率优化,设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和这个点的值都改回来。


    CODE:

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 using namespace std;
     5 const int N = 3e5 + 12;
     6 typedef long long LL;
     7 int n,dt,head[N],que[N];
     8 LL f[N],d[N],v[N],w[N];
     9 struct Edge
    10 {
    11     int to,nex;
    12     LL w;
    13 } edge[N << 1];
    14 void AddEdge(int u,int v,LL w)
    15 {
    16     edge[++dt] = (Edge)
    17     {
    18         v,head[u],w
    19     };
    20     head[u] = dt;
    21 }
    22 LL x(int i)
    23 {
    24     return d[i];
    25 }
    26 LL y(int i)
    27 {
    28     return f[i];
    29 }
    30 LL Get(int A,int B)
    31 {
    32     return f[A] + (d[B] - d[A]) * v[B] + w[B];
    33 }
    34 double slope(int A,int B)
    35 {
    36     return ((double)(y(B) - y(A))) / ((double)(x(B) - x(A)));
    37 }
    38 bool Cross(int A,int B,int C)
    39 {
    40     return slope(B,C) <= slope(A,B);
    41 }
    42 int find(int x,int tp)
    43 {
    44     int l=1,r=tp-1,ret=tp,mid;
    45     // 注意ret初始值
    46     while(l <= r)
    47     {
    48         mid = l + r >> 1;
    49         if(slope(que[mid],que[mid+1]) > (double)v[x]) ret=mid,r=mid-1;
    50         else l = mid + 1;
    51     }
    52     return ret;
    53 }
    54 
    55 int Find(int z,int tp)
    56 {
    57     int l=0,r=tp-1,ret=tp+1;
    58     // 注意ret初始值
    59     while(l<=r)
    60     {
    61         int mid =l+r>>1;
    62         if(slope(que[mid],z)<=slope(que[mid],que[mid+1]))ret=mid+1,r=mid-1;
    63         else l=mid+1;
    64     }
    65     return ret;
    66 }
    67 
    68 void dfs(int u,int pos,int fa)
    69 {
    70     int qpos,qtop;
    71     f[u] = Get(que[find(u,pos)],u);
    72     qpos = Find(u,pos);
    73     qtop = que[qpos];
    74     que[qpos] = u;
    75     for(int i = head[u]; i; i = edge[i].nex)
    76     {
    77         if(edge[i].to == fa)continue;
    78         d[edge[i].to] = d[u] + edge[i].w;
    79         dfs(edge[i].to,qpos,u);
    80     }
    81     que[qpos] = qtop;
    82 }
    83 int main()
    84 {
    85     scanf("%d",&n);
    86     int x,y,z;
    87     for(int i = 1; i < n; i++)
    88     {
    89         scanf("%d %d %d",&x,&y,&z);
    90         AddEdge(x,y,z);
    91         AddEdge(y,x,z);
    92     }
    93     for(int i = 2; i <= n; i++)scanf("%lld %lld",&w[i],&v[i]);
    94     dfs(1,0,0);
    95     printf("%lld",f[2]);
    96     for(int i = 3; i <= n; i++)printf(" %lld",f[i]);
    97 }
  • 相关阅读:
    2008年10月小记(SQL删除重复记录,生成表结构,字符串特性,statistics io)
    mysql 中 @
    使用单个innodb表,实现锁,防止游戏被刷物品或者其它资源!
    PSL
    8年PHP,懂点内核, 能写PHP扩展,5年网站经历+3年webgame经历,找个兼职
    Php aes算法
    MySQL触发器自动更新memcache
    怎么配置MySQL服务器(Incorrect string value)
    使用 PHP 将 XML 转化为易读的数组!
    使用Valgrind 查找内存泄露
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/11144226.html
Copyright © 2011-2022 走看看