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 31 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
40150
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 ] ); }
相关文章推荐
- bzoj3672 [Noi2014]购票
- 【BZOJ 3672】[Noi2014]购票 树分治+斜率优化
- bzoj 3672: [Noi2014]购票
- bzoj 3672: [Noi2014]购票
- bzoj3672 [Noi2014]购票
- [BZOJ3672][NOI2014]购票 树分治斜率优化
- bzoj千题计划251:bzoj3672: [Noi2014]购票
- [bzoj3672] [Noi2014]购票
- BZOJ 3672 NOI2014 购票 树的分治 NOI2014全AC达成!!!!
- BZOJ 3672 [Noi2014]购票 (熟练剖分+凸壳维护)
- BZOJ3672 : [Noi2014]购票
- bzoj 3672: [Noi2014]购票 树链剖分+维护凸包
- bzoj3672 [Noi2014]购票
- BZOJ3672: [Noi2014]购票
- ●BZOJ 3672 [Noi2014]购票
- 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**
- BZOJ 3672 [Noi2014]购票【点分+斜率优化
- bzoj 3672 [Noi2014]购票 (线段树+凸壳)
- BZOJ 3672 NOI2014 购票
- [Noi2014]购票 BZOJ3672 点分治+斜率优化+CDQ分治