bzoj 3672 利用点分治将CDQ分治推广到树型结构上
2015-05-16 16:02
281 查看
最大的收获就是题目所说。
deal(s) : 处理节点s所在块的问题,并保证:
1、s是该块中最靠近根节点的点,没有之一。
2、s所在块到根节点的路径上的点全都用来更新过了s所在块的所有节点。
然后步骤是:
1、找s所在块的重心c。
2、如果s就是c,那么用c更新当前块的所有节点,然后“删除c”,递归处理新产生的子块。
3、否则,删除c,deal(s),用c到s的路径(不包括c,包括s)更新c除了s子块的其他子块以及c,然后再用c去更新一次。
4、递归处理其它子块。
View Code
deal(s) : 处理节点s所在块的问题,并保证:
1、s是该块中最靠近根节点的点,没有之一。
2、s所在块到根节点的路径上的点全都用来更新过了s所在块的所有节点。
然后步骤是:
1、找s所在块的重心c。
2、如果s就是c,那么用c更新当前块的所有节点,然后“删除c”,递归处理新产生的子块。
3、否则,删除c,deal(s),用c到s的路径(不包括c,包括s)更新c除了s子块的其他子块以及c,然后再用c去更新一次。
4、递归处理其它子块。
#include <cstdio> #include <cassert> #include <cstring> #include <algorithm> #define N 200010 #define M N<<1 #define fill(arr,lf,rg,v) memset(arr+lf,v,sizeof(arr[0])*(rg-lf+1)) using namespace std; typedef long long dnt; struct Vector { dnt x, y; Vector(){} Vector( dnt x, dnt y ):x(x),y(y){} Vector operator+( const Vector &o ) const { return Vector(x+o.x,y+o.y); } Vector operator-( const Vector &o ) const { return Vector(x-o.x,y-o.y); } double operator^( const Vector &o ) const { return (double)x*o.y-(double)y*o.x; } }; typedef Vector Point; bool onleft( const Point &a, const Point &b, const Point &c ) { return ((b-a)^(c-a)) >= 0.0; } struct Convex { Point stk ; int top; void init() { top=-1; } inline void append( const Point &p ) { while( top>0 && onleft(stk[top-1],stk[top],p) ) top--; stk[++top] = p; } const Point& query( dnt k ) { int lf=0; int rg=top; if( lf==rg ) return stk[top]; assert(k*(stk[lf].x-stk[lf+1].x)>=0); if( k*(stk[lf].x-stk[lf+1].x) >= (stk[lf].y-stk[lf+1].y) ) return stk[lf]; assert(k*(stk[rg-1].x-stk[rg].x)>=0); if( k*(stk[rg-1].x-stk[rg].x) <= (stk[rg-1].y-stk[rg].y) ) return stk[rg]; lf++; rg--; while( lf<rg ) { int mid=(lf+rg)>>1; assert(k*(stk[mid].x-stk[mid+1].x)>=0); if( k*(stk[mid].x-stk[mid+1].x) > (stk[mid].y-stk[mid+1].y) ) rg=mid; else lf=mid+1; } return stk[lf]; } }; int n, case_type; int head , next[M], dest[M], etot; dnt wp , wq , lim , ws[M]; int anc , fat , vis , siz , bac ; dnt dep , dp ; int qu , bg, ed; Convex convex; void adde( int u, int v, dnt s ) { etot++; dest[etot] = v; next[etot] = head[u]; ws[etot] = s; head[u] = etot; } void bfs( int s ) { qu[bg=ed=1] = s; anc[s] = 0; dep[s] = 0; while( bg<=ed ) { int u=qu[bg++]; for( register int t=head[u]; t; t=next[t] ) { int v=dest[t]; if( v==anc[u] ) continue; qu[++ed] = v; anc[v] = u; dep[v] = dep[u]+ws[t]; } } } int getc( int s ) { qu[bg=ed=1] = s; fat[s] = 0; bac[s] = 0; siz[s] = 0; while( bg<=ed ) { int u=qu[bg++]; for( register int t=head[u]; t; t=next[t] ) { int v=dest[t]; if( vis[v] || v==fat[u] ) continue; qu[++ed] = v; fat[v] = u; bac[v] = 0; siz[v] = 0; } } int c = 0; for( register int i=ed; i>=1; i-- ) { int u=qu[i]; siz[u]++; if( fat[u] ) { int f=fat[u]; siz[f]+=siz[u]; if( siz[u]>bac[f] ) bac[f]=siz[u]; } } for( register int i=1; i<=ed; i++ ) { int u=qu[i]; if( bac[u]<siz[s]-siz[u] ) bac[u]=siz[s]-siz[u]; if( !c || bac[u]<bac[c] ) c=u; } //fprintf( stderr, "%d\n", c ); return c; } void flood( int s ) { qu[bg=ed=1] = s; fat[s] = 0; while( bg<=ed ) { int u=qu[bg++]; for( register int t=head[u]; t; t=next[t] ) { int v=dest[t]; if( vis[v] || v==fat[u] ) continue; qu[++ed] = v; fat[v] = u; } } } inline void update( const Point &p, int u ) { dnt v = p.y + wp[u]*(dep[u]-p.x) + wq[u]; if( dp[u]>v ) dp[u]=v; } bool cmp( int a, int b ) { return dep[a]-lim[a]>dep[b]-lim[b]; } void vdcp( int s ) { int c=getc(s); vis[c] = true; if( c==s ) { Point pc = Point(dep[c],dp[c]); flood(s); for( int i=1; i<=ed; i++ ) { int u=qu[i]; if( u!=s && dep[u]-lim[u]<=pc.x ) update(pc,u); } } else { vdcp(s); flood(c); sort( qu+1, qu+1+ed, cmp ); convex.init(); int cur = c; for( register int i=1; i<=ed; i++ ) { int u=qu[i]; while( cur!=s && dep[anc[cur]]>=dep[u]-lim[u] ) { cur=anc[cur]; convex.append( Point(dep[cur],dp[cur]) ); } if( convex.top>=0 ) update( convex.query(wp[u]), u ); } Point cp = Point(dep[c],dp[c]); for( register int i=ed; i>=1; i-- ) { int u=qu[i]; if( u==c ) continue; if( dep[u]-lim[u]>dep[c] ) break; update( cp, u ); } } for( int t=head[c]; t; t=next[t] ) { int v=dest[t]; if( vis[v] ) continue; vdcp(v); } } int main() { scanf( "%d%d", &n, &case_type ); for( int i=2; i<=n; i++ ) { int f; dnt s; scanf( "%d%lld%lld%lld%lld", &f, &s, wp+i, wq+i, lim+i ); adde( f, i, s ); adde( i, f, s ); } fill( dp, 0, n, 0x3f ); dp[1] = 0; bfs(1); vdcp(1); for( int i=2; i<=n; i++ ) printf( "%lld\n", dp[i] ); }
View Code
相关文章推荐
- [BZOJ3672][NOI2014]购票-点分治-CDQ分治-斜率优化DP
- bzoj 3672: [Noi2014]购票 树上cdq分治
- bzoj3672 [ NOI2014 ] -- 树上CDQ分治 + 斜率优化DP
- 【BZOJ 3672】 3672: [Noi2014]购票 (CDQ分治+点分治+斜率优化)**
- [BZOJ 2253][2010 Beijing wc]纸箱堆叠:CDQ分治|DP
- bzoj 1176 [Balkan2007]Mokia 【CDQ分治】
- 【BZOJ2253】纸箱堆叠 [CDQ分治]
- BZOJ 2716: [Violet 3]天使玩偶 [CDQ分治]
- 【bzoj 1176】Mokia(CDQ分治)
- [学习笔记]CDQ分治 bzoj1176 [Baltic2007] Mokia
- 利用 zTree 在 MVC 下实现树型结构管理
- NOI 2007 货币兑换Cash (bzoj 1492) - 斜率优化 - 动态规划 - CDQ分治
- bzoj1492 斜率优化|cdq分治
- [BZOJ3262]陌上花开(cdq分治+讲解+小结)
- BZOJ 1176 [Balkan2007]Mokia ——CDQ分治
- 【CDQ分治】 BZOJ3262 陌上花开
- [BZOJ3963][WF2011][CDQ分治][斜率优化][DP]MachineWorks
- BZOJ 1176 Mokia(CDQ分治)
- BZOJ 2683: 简单题【CDQ分治 + 树状数组
- bzoj 2961: 共点圆 cdq分治