3784: 树上的路径
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 511 Solved: 171
[ Submit][ Status][ Discuss]
Description
给定一个N个结点的树,结点用正整数1..N编号。每条边有一个正整数权值。用d(a,b)表示从结点a到结点b路边上经过边的权值。其中要求a<b.将这n*(n-1)/2个距离从大到小排序,输出前M个距离值。
Input
第一行两个正整数N,M
下面N-1行,每行三个正整数a,b,c(a,b<=N,C<=10000)。表示结点a到结点b有一条权值为c的边。
Output
共M行,如题所述.
Sample Input
5 10
1 2 1
1 3 2
2 4 3
2 5 4
1 2 1
1 3 2
2 4 3
2 5 4
Sample Output
7
7
6
5
4
4
3
3
2
1
7
6
5
4
4
3
3
2
1
HINT
N<=50000,M<=Min(300000,n*(n-1) /2 )
Source
题解:
我的算法好像又和网上的不一样。。。
%peehs一眼秒了这题。
先二分长度小于等于ans的路径有几条。
这个可以用树分治做,为了方便,用边分治。分治时暴力枚举被切开的边的一边的点,另一边二分找有几个满足要求的。
时间复杂度O(nlog^3n)。
考虑把第二个二分去掉。先预处理出边分治的结果(把两个到根的距离数组排序),之后枚举一边的点时,另一边是单调的,所以一起扫一遍就可以了。
时间复杂度O(nlog^2n),空间复杂度O(nlogn)。
#include <stdio.h>
#include <algorithm>
using namespace std;
//long long
const long long maxn = 51000;
const long long maxm = 310000;
struct so {
long long l[3] , r[3] , f , len;
} s[maxn*18];
struct node {
long long v , taboo , c;
node *next , *rev;
} poolo[maxn*5] , pool[maxn*5] , *og[maxn*2] , *g[maxn*2];
long long topo , top , topver , topa;
long long n , m;
long long next[maxn*2];
long long a[maxn*50] , index;
long long siz[maxn*2];
long long ans[maxm] , topans;
bool cmp ( long long x1 , long long x2 ) {
return x1 > x2;
}
void addo ( long long u , long long v , long long c ) {
node *tmp1 = &poolo[++topo] , *tmp2 = &poolo[++topo];
tmp1 -> v = v; tmp1 -> c = c; tmp1 -> next = og[u]; og[u] = tmp1; tmp1 -> rev = tmp2;
tmp2 -> v = u; tmp2 -> c = c; tmp2 -> next = og[v]; og[v] = tmp2; tmp2 -> rev = tmp1;
}
void add ( long long u , long long v , long long c ) {
//printf ( "%lld %lld %lld\n" , u , v , c );
node *tmp1 = &pool[++top] , *tmp2 = &pool[++top];
tmp1 -> v = v; tmp1 -> c = c; tmp1 -> next = g[u]; g[u] = tmp1; tmp1 -> rev = tmp2;
tmp2 -> v = u; tmp2 -> c = c; tmp2 -> next = g[v]; g[v] = tmp2; tmp2 -> rev = tmp1;
}
void rebuild ( long long i , long long from ) {
for ( node *j = og[i] ; j ; j = j -> next ) if ( j -> v != from ) {
//printf ( "%d %d\n" , i , j -> v );
add ( next[i] , ++topver , 0 );
add ( topver , j -> v , j -> c );
next[i] = topver;
rebuild ( j -> v , i );
}
}
void dfs1 ( long long i , long long from ) {
siz[i] = 1;
for ( node *j = g[i] ; j ; j = j -> next ) if ( j -> v != from & j -> taboo == 0 ) {
dfs1 ( j -> v , i );
siz[i] += siz[j->v];
}
}
node *getroot ( long long i , long long from , long long all , node *ret ) {
node *tmp = NULL;
for ( node *j = g[i] ; j ; j = j -> next ) if ( j -> v != from && j -> taboo == 0 ) {
if ( siz[j->v] * 2 >= all ) return getroot ( j -> v , i , all , j );
else {
if ( tmp == NULL || siz[tmp->v] < siz[j->v] ) tmp = j;
}
}
if ( ret == NULL ) return tmp;
else return ret;
}
void dfs2 ( long long i , long long from , long long sum ) {
if ( i <= n ) a[++topa] = sum;
for ( node *j = g[i] ; j ; j = j -> next ) if ( j -> v != from && j -> taboo == 0 ) {
dfs2 ( j -> v , i , sum + j -> c );
}
}
void split ( long long i ) {
dfs1 ( i , -1 );
if ( siz[i] == 1 ) return ;
node *tmp = getroot ( i , -1 , siz[i] , NULL );
//printf ( "%lld %lld %lld %lld \n" , i , siz[i] , tmp -> v , tmp -> rev -> v );
tmp -> taboo = 1; tmp -> rev -> taboo = 1;
++index;
s[index].len = tmp -> c;
s[index].l[1] = topa + 1;
dfs2 ( tmp -> v , -1 , 0 );
s[index].r[1] = topa;
s[index].l[2] = topa + 1;
dfs2 ( tmp -> rev -> v , -1 , 0 );
s[index].r[2] = topa;
//printf ( "%lld %lld %lld %lld %lld len%lld\n" , index , s[index].l[1] , s[index].r[1] , s[index].l[2] , s[index].r[2] , s[index].len);
if ( s[index].l[1] > s[index].r[1] || s[index].l[2] > s[index].r[2] ) s[index].f = 0;
else {
s[index].f = 1;
sort ( a + s[index].l[1] , a + 1 + s[index].r[1] , cmp );
sort ( a + s[index].l[2] , a + 1 + s[index].r[2] , cmp );
}
//for ( i = s[index].l[1] ; i <= s[index].r[1] ; i++ ) printf ( "%d " , a[i] );
//printf ( "\n" );
//for ( i = s[index].l[2] ; i <= s[index].r[2] ; i++ ) printf ( "%d " , a[i] );
//printf ( "\n" );
//printf ( "%d\n" , s[index].f );
split ( tmp -> v ); split ( tmp -> rev -> v );
}
long long check ( long long x ) {
long long i , j , k , sum = 0;
for ( i = 1 ; i <= index ; i++ ) {
if ( s[i].f == 0 ) continue;
k = s[i].r[2];
for ( j = s[i].l[1] ; j <= s[i].r[1] ; j++ ) {
while ( k > s[i].l[2] && a[k] + a[j] + s[i].len < x ) k--;
if ( a[k] + a[j] + s[i].len >= x ) sum += k - s[i].l[2] + 1;
//printf ( "%lld %lld\n" , s[i].l[2] , x );
}
}
return sum;
}
void find ( long long x ) {
//printf ( "%lld\n" ,x );
long long i , j , k;
for ( i = 1 ; i <= index ; i++ ) {
if ( s[i].f == 0 ) continue;
for ( j = s[i].l[1] ; j <= s[i].r[1] ; j++ ) {
for ( k = s[i].l[2] ; k <= s[i].r[2] ; k++ ) {
if ( a[j] + a[k] + s[i].len <= x ) break;
//if ( i == 22 ) printf ( "## %lld\n" , a[j] + a[k] + s[i].len );
ans[++topans] = a[j] + a[k] + s[i].len;
}
}
}
}
void work () {
long long i , u , v , c , l , r , mid , x;
scanf ( "%lld%lld" , &n , &m );
for ( i = 1 ; i < n ; i++ ) {
scanf ( "%lld%lld%lld" , &u , &v , &c );
addo ( u , v , c );
}
for ( i = 1 ; i <= n ; i++ ) next[i] = i;
topver = n;
rebuild ( 1 , 0 );
split ( 1 );
l = 0; r = 510000000;
while ( l < r - 1 ) {
mid = (l+r)/2;
if ( check ( mid ) < m ) r = mid;
else l = mid;
}
topans = 0;
if ( check ( l ) < m ) find ( r ), x = r;
else find ( l ), x = l;
for ( i = topans + 1 ; i <= m ; i++ ) ans[i] = x;
sort ( ans + 1 , ans + 1 + m );
for ( i = m ; i >= 1 ; i-- ) printf ( "%lld\n" , ans[i] );
}
int main () {
//FILE *fpr = freopen ( "bzoj3784.in" , "r" , stdin );
//FILE *fpw = freopen ( "bzoj3784.out" , "w" , stdout );
work ();
return 0;
}