题目大意
给定一棵
n
个点的树,对于每个点求到它距离第
Data Constraint
n≤10000
题解
先二分一个答案,现在要快速的找有多少个距离小于等于二分的答案。
所以先构出点剖树,然后在树上跑,每次在排好序的距离队列中二分。
时间复杂度: O(nlog3n)
SRC
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std ;
#define N 10000 + 10
const int MAXN = 15 ;
struct Note {
vector < int > dis ;
} tp ;
vector < int > P[N] ;
vector < Note > Q[N] ;
bool vis[N] ;
int Node[2*N] , Next[2*N] , Len[2*N] , Head[N] , tot ;
int Size[N] , Maxs[N] , Pre[N] , Cnt[N] , From[N] ;
int Deep[N] , Dist[N] , f[N][MAXN] ;
int All , Root , Minv , ans ;
int n ;
void link( int u , int v , int w ) {
Node[++tot] = v ;
Len[tot] = w ;
Next[tot] = Head[u] ;
Head[u] = tot ;
}
void GetSize( int x , int F ) {
Size[x] = Maxs[x] = 1 ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
GetSize( Node[p] , x ) ;
Size[x] += Size[Node[p]] ;
if ( Size[Node[p]] > Maxs[x] ) Maxs[x] = Size[Node[p]] ;
}
}
void GetRoot( int x , int F ) {
Maxs[x] = max( Maxs[x] , Size[All] - Maxs[x] ) ;
if ( Maxs[x] < Minv ) Minv = Maxs[x] , Root = x ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
GetRoot( Node[p] , x ) ;
}
}
void DFS1( int x , int F ) {
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
Dist[Node[p]] = Dist[x] + Len[p] ;
P[Root].push_back( Dist[Node[p]] ) ;
DFS1( Node[p] , x ) ;
}
}
void DFS2( int x , int F ) {
tp.dis.push_back( Dist[x] ) ;
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == F || vis[Node[p]] ) continue ;
Dist[Node[p]] = Dist[x] + Len[p] ;
DFS2( Node[p] , x ) ;
}
}
void DIV( int x , int F , int h ) {
GetSize( x , 0 ) ;
Minv = 0x7FFFFFFF ;
Root = All = x ;
GetRoot( x , 0 ) ;
Pre[Root] = F ;
vis[Root] = 1 ;
Dist[Root] = 0 ;
From[Root] = h ;
P[Root].push_back( 0 ) ;
for (int p = Head[Root] ; p ; p = Next[p] ) {
if ( vis[Node[p]] ) continue ;
Dist[Node[p]] = Dist[Root] + Len[p] ;
P[Root].push_back( Dist[Node[p]] ) ;
DFS1( Node[p] , 0 ) ;
}
sort( P[Root].begin() , P[Root].end() ) ;
int now = Root ;
for (int p = Head[now] ; p ; p = Next[p] ) {
if ( vis[Node[p]] ) continue ;
Dist[Node[p]] = Len[p] ;
tp.dis.clear() ;
DFS2( Node[p] , 0 ) ;
sort( tp.dis.begin() , tp.dis.end() ) ;
Q[now].push_back(tp) ;
DIV( Node[p] , now , Cnt[now] ) ;
Cnt[now] ++ ;
}
}
void Search( int x ) {
for (int p = Head[x] ; p ; p = Next[p] ) {
if ( Node[p] == f[x][0] ) continue ;
Deep[Node[p]] = Deep[x] + 1 ;
Dist[Node[p]] = Dist[x] + Len[p] ;
f[Node[p]][0] = x ;
Search( Node[p] ) ;
}
}
int LCA( int x , int y ) {
if ( Deep[x] < Deep[y] ) swap( x , y ) ;
for (int i = MAXN - 1 ; i >= 0 ; i -- ) {
if ( Deep[f[x][i]] >= Deep[y] ) x = f[x][i] ;
}
if ( x == y ) return x ;
for (int i = MAXN - 1 ; i >= 0 ; i -- ) {
if ( f[x][i] != f[y][i] ) x = f[x][i] , y = f[y][i] ;
}
return f[x][0] ;
}
int GetDist( int x , int y ) { return Dist[x] + Dist[y] - 2 * Dist[LCA(x,y)] ; }
int Count( vector < int > p , int val ) {
int ret = upper_bound( p.begin() , p.end() , val ) - p.begin() ;
return ret ;
}
int Calc( int x , int len ) {
int ret = 0 ;
int now = x , last = 0 ;
while ( now ) {
int del = GetDist( now , x ) ;
ret += Count( P[now] , len - del ) ;
if ( last ) ret -= Count( Q[now][From[last]].dis , len - del ) ;
last = now ;
now = Pre[now] ;
}
return ret ;
}
int main() {
freopen( "treekth.in" , "r" , stdin ) ;
freopen( "treekth.out" , "w" , stdout ) ;
scanf( "%d" , &n ) ;
for (int i = 1 ; i < n ; i ++ ) {
int u , v , w ;
scanf( "%d%d%d" , &u , &v , &w ) ;
link( u , v , w ) ;
link( v , u , w ) ;
}
DIV( 1 , 0 , 0 ) ;
Deep[1] = Dist[1] = 0 ;
Search( 1 ) ;
for (int j = 1 ; j < MAXN ; j ++ ) {
for (int i = 1 ; i <= n ; i ++ ) f[i][j] = f[f[i][j-1]][j-1] ;
}
for (int i = 1 ; i <= n ; i ++ ) {
int K ;
scanf( "%d" , &K ) ;
ans = -1 ;
int l = 0 , r = 1e9 ;
while ( l <= r ) {
int mid = (l + r) / 2 ;
if ( Calc( i , mid ) >= K ) ans = mid , r = mid - 1 ;
else l = mid + 1 ;
}
printf( "%d\n" , ans ) ;
}
return 0 ;
}
以上.