您的位置:首页 > 其它

BZOJ3672: [Noi2014]购票

2017-02-21 15:39 441 查看

Description

 今年夏天,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他们所花的最少资金是多少。

Input

第 1 行包含2个非负整数 n,t,分别表示城市的个数和数据类型(其意义将在后面提到)。输入文件的第 2 到 n 行,每行描述一个除SZ之外的城市。其中第 v 行包含 5 个非负整数 f_v,s_v,p_v,q_v,l_v,分别表示城市 v 的父亲城市,它到父亲城市道路的长度,票价的两个参数和距离限制。请注意:输入不包含编号为 1 的SZ市,第 2 行到第 n 行分别描述的是城市 2 到城市 n。

Output

输出包含 n-1 行,每行包含一个整数。其中第 v 行表示从城市 v+1 出发,到达SZ市最少的购票费用。同样请注意:输出不包含编号为 1 的SZ市。

 

Sample Input

7 3

1 2 20 0 3

1 5 10 100 5

2 4 10 10 10

2 9 1 100 10

3 5 20 100 10

4 4 20 0 10

Sample Output

40

150

70

149

300

150

HINT

 



对于所有测试数据,保证 0≤pv≤106,0≤qv≤1012,1≤fv<v;保证 0<sv≤lv≤2×1011,且任意城市到SZ市的总路程长度不超过 2×1011。

输入的 t 表示数据类型,0≤t<4,其中:

当 t=0 或 2 时,对输入的所有城市 v,都有 fv=v-1,即所有城市构成一个以SZ市为终点的链;

当 t=0 或 1 时,对输入的所有城市 v,都有 lv=2×1011,即没有移动的距离限制,每个城市都能到达它的所有祖先;

当 t=3 时,数据没有特殊性质。

n=2×10^5

Source

树分治+斜率优化
首先如果在序列上会很好做,直接斜率优化
然后考虑在树上进行分治
选取重心,把上面的一块递归处理
然后重心下面的节点按能到达的最上面的地方排序,就可以two-pointer扫了
这样dis是单调的,维护一个下凸包,询问的时候就直接upper_bound就好了
然后把下面的继续分治
我更新重心的时候,向上跳写成了直接跳到原树的根,本来应该跳到原树的重心的...
一直T直到我去人眼FC标程
#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int MAXN = 200010;
const LL INF = 1e18;

struct edge { int to, nxt; LL val; }e[MAXN << 1];

inline int read()
{
int sc = 0; char ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();
return sc;
}

inline LL Read()
{
LL sc = 0; char ch = getchar();
while( ch < '0' || ch > '9' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();
return sc;
}

int head[MAXN], cnt, f[MAXN], n, YJQ, g[MAXN], size[MAXN];
int tmp[MAXN], tot, st[MAXN], top;
double k[MAXN];
LL p[MAXN], q[MAXN], dp[MAXN], dis[MAXN], l[MAXN];
bool vis[MAXN];

inline bool cmp(int x, int y) { return dis[ x ] - l[ x ] > dis[ y ] - l[ y ]; }

inline void addedge(int x, int y, LL w) { e[ ++cnt ].to = y; e[ cnt ].nxt = head[ x ]; head[ x ] = cnt; e[ cnt ].val = w; }

inline void Dfs(int x)
{
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
dis[ e[ i ].to ] = dis[ x ] + e[ i ].val, Dfs( e[ i ].to );
}

inline void findroot(int x, int Size, int &cg)
{
size[ x ] = 1; g[ x ] = 0;
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] )
{
findroot( e[ i ].to, Size, cg );
size[ x ] += size[ e[ i ].to ];
g[ x ] = max( g[ x ], size[ e[ i ].to ] );
}
g[ x ] = max( g[ x ], Size - size[ x ] );
if( g[ x ] < g[ cg ] ) cg = x;
}

inline void dfs(int x)
{
tmp[ ++tot ] = x;
for( int i = head[ x ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] ) dfs( e[ i ].to );
}

inline double slope(int x, int y) { return ( double ) ( dp[ x ] - dp[ y ] ) / ( double ) ( dis[ x ] - dis[ y ] ); }

inline void insert(int x)
{
while( top > 1 && slope( x, st[ top ] ) > slope( st[ top ], st[ top - 1 ] ) ) top--;
st[ ++top ] = x; k[ top ] = -slope( x, st[ top - 1 ] );
}

inline void solve(int x, int Size, int tim)
{
if( Size <= 1 ) return ;
int cg = 0; findroot( x, Size, cg );
vis[ cg ] = 1;
solve( x, Size - size[ cg ], tim + 1 );
//printf( "[x=%d cg=%d Size=%d]\n", x, cg, Size );
for( int i = f[ cg ] ; i ^ f[ x ] ; i = f[ i ] )
if( dis[ cg ] - dis[ i ] <= l[ cg ] )
dp[ cg ] = min( dp[ cg ], dp[ i ] + ( dis[ cg ] - dis[ i ] ) * p[ cg ] + q[ cg ] );
else break;
tot = top = 0;
for( int i = head[ cg ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] ) dfs( e[ i ].to );
sort( tmp + 1, tmp + tot + 1, cmp );
//for( int i = 1 ; i <= tot ; i++ ) printf( "%d ", tmp[ i ] ); putchar( 10 );
for( int i = 1, j = cg ; i <= tot ; i++ )
{
while( j != f[ x ] && dis[ j ] >= dis[ tmp[ i ] ] - l[ tmp[ i ] ] ) insert( j ), j = f[ j ];
//printf( "%d %d\n", j, i );
if( top == 1 )
dp[ tmp[ i ] ] = min( dp[ tmp[ i ] ], dp[ st[ 1 ] ] + ( dis[ tmp[ i ] ] - dis[ st[ 1 ] ] ) * p[ tmp[ i ] ] + q[ tmp[ i ] ] );
else if( top )
{
int cur = upper_bound( k + 2, k + top + 1, -p[ tmp[ i ] ] ) - k - 1;
//printf( "cur = %d top = %d\n", cur, top );
dp[ tmp[ i ] ] = min( dp[ tmp[ i ] ], dp[ st[ cur ] ] + ( dis[ tmp[ i ] ] - dis[ st[ cur ] ] ) * p[ tmp[ i ] ] + q[ tmp[ i ] ] );
}
}
//putchar( 10 );
for( int i = head[ cg ] ; i ; i = e[ i ].nxt )
if( !vis[ e[ i ].to ] ) vis[ e[ i ].to ] = 1, solve( e[ i ].to, size[ e[ i ].to ], tim + 1 );
}

int main()
{
n = read(); YJQ = read(); g[ 0 ] = 1e9;
for( int i = 2 ; i <= n ; i++ )
{
f[ i ] = read(); addedge( f[ i ], i, Read() );
p[ i ] = Read(); q[ i ] = Read(); l[ i ] = Read();
}
Dfs( 1 );
for( int i = 2 ; i <= n ; i++ ) dp[ i ] = INF;
solve( 1, n, 0 );
for( int i = 2 ; i <= n ; i++ ) printf( "%lld\n", dp[ i ] );
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: