Description
给定一棵
n
n
n 个节点的树,点的标号为
1..
n
1..n
1 . . n ,边有边权。 记
d
(
u
,
v
)
d(u, v)
d ( u , v ) 为
u
u
u 到
v
v
v 的路径上边的权值和,对于每个节点
u
u
u ,你需要给出一个
m
m
m 维 向量
p
u
=
pu =
p u = {
p
u
,
1
,
.
.
,
p
u
,
m
p_{u,1}, .., p_{u,m}
p u , 1 , . . , p u , m }。 使得对于任意点对
u
,
v
u,v
u , v ,满足
d
(
u
,
v
)
=
m
a
x
∣
p
u
,
i
−
p
v
,
i
∣
d(u, v) = max{|p_{u,i} − p_{v,i}|}
d ( u , v ) = m a x ∣ p u , i − p v , i ∣ 。
n
<
=
1000
n<=1000
n < = 1 0 0 0
Solution
刚开始看错题意了QwQ,没有注意到向量的位置是对应的。 暴力的构造一个答案的方法就是直接以每一个点为根多一维,每一个点在这一维的值即为它的深度。 我们可以通过调整根的选择和正负号来使得维数最少。 点分治。点分治的每一层就是每一维,最后的维数就是层数。 每一次将儿子分成尽量均匀的两块,一边是
−
d
e
p
,
-dep,
− d e p , 一边是
d
e
p
dep
d e p ,这样子这两边互相就可以满足了,这样就只用考虑子问题了。 不同的两块可能在这一维有共点。直接给边赋权值,从一个点开始统一就好了。 注意到会不会子问题的答案之间互相影响会不会超过两两的距离。实际上是每条边的*+1或-1加在一起,肯定不会超过全部正或全部负。 那么一共有多少层呢? 结论是每一次至少分n/3. 首先重儿子的大小<=n/2,如果最大重儿子sz>=n/3,得证。如果最大重儿子sz<n/3,那么每多一个儿子在n/3以内,最后平均的大小是不会超过2*n/3的,得证。 每一次大小至少乘2/3,对于1000正好有16层。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define maxn 1005
using namespace std;
int n, i, j, k, x, y, z;
int em, e[ maxn* 2 ] , nx[ maxn* 2 ] , ls[ maxn] , ec[ maxn* 2 ] , h[ 20 ] [ maxn* 2 ] ;
int bz[ maxn] , ans[ 20 ] [ maxn] ;
void insert ( int x, int y, int z) {
em++ ; e[ em] = y; nx[ em] = ls[ x] ; ls[ x] = em; ec[ em] = z;
em++ ; e[ em] = x; nx[ em] = ls[ y] ; ls[ y] = em; ec[ em] = z;
}
int g, sz[ maxn] , All;
void Getg ( int x, int p) {
int mx= 0 ; sz[ x] = 1 ;
for ( int i= ls[ x] ; i; i= nx[ i] ) if ( e[ i] != p&& ! bz[ e[ i] ] )
Getg ( e[ i] , x) , sz[ x] + = sz[ e[ i] ] , mx= max ( mx, sz[ e[ i] ] ) ;
mx= max ( mx, All- sz[ x] ) ;
if ( mx<= All/ 2 ) g= x;
}
void Getsz ( int x, int p) {
sz[ x] = 1 ;
for ( int i= ls[ x] ; i; i= nx[ i] ) if ( e[ i] != p&& ! bz[ e[ i] ] )
Getsz ( e[ i] , x) , sz[ x] + = sz[ e[ i] ] ;
}
int tot;
struct node{ int x, sz; } A[ maxn] ;
int cmp ( node a, node b) { return a. sz> b. sz; }
int nowdep, maxdep;
void Cover ( int x, int p, int k) {
for ( int i= ls[ x] ; i; i= nx[ i] ) if ( ! bz[ e[ i] ] ) {
if ( e[ i] == p) h[ nowdep] [ i] = - k* ec[ i] , h[ nowdep] [ i^ 1 ] = k* ec[ i] ;
else Cover ( e[ i] , x, k) ;
}
}
int d0[ 20 ] [ maxn] , d1[ 20 ] [ maxn] ;
void Doit ( int now, int all, int depth) {
if ( all== 1 ) { bz[ now] = 1 ; return ; }
int i; maxdep= max ( maxdep, depth) ;
All= all, Getg ( now, 0 ) ;
Getsz ( g, 0 ) ;
for ( tot= 0 , i= ls[ g] ; i; i= nx[ i] ) if ( ! bz[ e[ i] ] )
tot++ , A[ tot] . x= e[ i] , A[ tot] . sz= sz[ e[ i] ] ;
sort ( A+ 1 , A+ 1 + tot, cmp) ;
int sum0= 0 , sum1= 0 ; nowdep= depth;
d0[ depth] [ 0 ] = d1[ depth] [ 0 ] = 0 ;
for ( i= 1 ; i<= tot; i++ ) if ( sum0< sum1)
sum0+ = A[ i] . sz, d0[ depth] [ ++ d0[ depth] [ 0 ] ] = A[ i] . x, Cover ( A[ i] . x, g, 1 ) ;
else sum1+ = A[ i] . sz, d1[ depth] [ ++ d1[ depth] [ 0 ] ] = A[ i] . x, Cover ( A[ i] . x, g, - 1 ) ;
int nowg= g;
if ( all- sum0> 2 ) {
for ( i= 1 ; i<= d0[ depth] [ 0 ] ; i++ ) bz[ d0[ depth] [ i] ] = 1 ;
Doit ( nowg, all- sum0, depth+ 1 ) ;
for ( i= 1 ; i<= d0[ depth] [ 0 ] ; i++ ) bz[ d0[ depth] [ i] ] = 0 ;
}
if ( all- sum1> 2 ) {
for ( i= 1 ; i<= d1[ depth] [ 0 ] ; i++ ) bz[ d1[ depth] [ i] ] = 1 ;
Doit ( nowg, all- sum1, depth+ 1 ) ;
for ( i= 1 ; i<= d1[ depth] [ 0 ] ; i++ ) bz[ d1[ depth] [ i] ] = 0 ;
}
}
void DFS ( int x, int p, int D, int tp) {
ans[ tp] [ x] = D;
for ( int i= ls[ x] ; i; i= nx[ i] ) if ( e[ i] != p)
DFS ( e[ i] , x, D+ h[ tp] [ i] , tp) ;
}
int main ( ) {
freopen ( "ceshi.in" , "r" , stdin ) ;
freopen ( "ceshi.out" , "w" , stdout ) ;
scanf ( "%d" , & n) ;
for ( em= 1 , i= 1 ; i< n; i++ )
scanf ( "%d%d%d" , & x, & y, & z) , insert ( x, y, z) ;
Doit ( 1 , n, 1 ) ;
for ( i= 1 ; i<= maxdep; i++ ) DFS ( 1 , 0 , 0 , i) ;
printf ( "%d\n" , maxdep) ;
for ( j= 1 ; j<= n; j++ , printf ( "\n" ) ) for ( i= 1 ; i<= maxdep; i++ ) printf ( "%d " , ans[ i] [ j] ) ;
}