您的位置:首页 > 其它

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、递归处理其它子块。

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: