Loading

题解—Lost my music

这道题咕了两个做法

  • 树剖线段树三分\(nlog^3n\)
  • 主席树维护单调栈可持久化

所以只学了一个神仙做法。

通过倍增来实现的可持久化单调栈。

由于题目让求的是一个斜率的负数\(\Large-\frac{c_v-c_u}{dep_v-dep_u}\)

所以答案就是一个斜率,我们想让答案尽量小,就是让斜率尽量大。

斜率大可以用单调栈维护一个下凸壳,遇到不合法的就弹栈直到合法,然后取栈顶计算答案。
之后把自己加进去,去递归自己的子孙们。

但是发现需要很多弹栈入栈,时间根本不允许。

所以由于单调栈里面是单调的,所以可以倍增弹栈。

但是发现还需要可持久化。

所以我们就不开出来这个栈,我们直接记录他在的凸壳上\(2^i\)级父亲是谁,然后跳就行了。
对于继承可持久化,我们直接在他父亲的凸壳上倍增找到第一个不合法的点,然后继承合法的部分,把自己再插进去,这个壳就成他的了。

所以就是自己开了一个\(2^i\)的副本,只有\(log\)级别。

code



#include <cstdio>
#include <algorithm>
#include <cstring>
#define R register int
#define int long
#define printf Ruusupuu = printf
#define scanf Ruusupuu = scanf
#define freopen rsp_5u = freopen

int Ruusupuu ;
FILE * rsp_5u ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef pair<int , int> PI ;
const int N = 5e5 + 10 ;

inline void of(){ freopen( "in.in" , "r" , stdin ) , freopen( "out.out" , "w" , stdout ) ; }
inline void cf(){ fclose( stdin ) , fclose( stdout ) ; }
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ; 
}

int n , d [N] , x , dep [N] ;
int fr [N] , to [N] , net [N] , head [N] , cnt = 1 ;
#define add( f , t ) fr [++ cnt] = f , to [cnt] = t , net [cnt] = head [f] , head [f] = cnt 

inline D cal( int x , int y ){ return 1.0 * ( d [x] - d [y] ) / ( dep [x] - dep [y] ) ; }

void sc(){
	n = read() , memset( head , -1 , sizeof( head ) ) ;
	for( R i = 1 ; i <= n ; i ++ ) d [i] = read() ;
	for( R i = 2 ; i <= n ; i ++ ) x = read() , add( x , i ) ;  
}

int fa [N] , top , las [N][25] ;
D ans [N] ;

void dfs( int x , int fh ){
	
	dep [x] = dep [fh] + 1 ;
	
	for( R i = 20 ; i >= 0 ; i -- )
		if( !las [fh][i] || !las [las [fh][i]][0] ) continue ;
		else if( cal( las [fh][i] , x ) <= cal( las[las [fh][i]][0] , x ) ) fh = las [fh][i] ; 
	
	if( fh != 1 && cal( fh , x ) <= cal( las [fh][0] , x ) ) fh = las [fh][0] ;
	
	las [x][0] = fh ;
	for( R i = 1 ; i <= 20 ; i ++ )
		las [x][i] = las [las [x][i - 1]][i - 1] ;
	
	for( R i = head [x] ; ~i ; i = net [i] )
		dfs( to [i] , x ) ;
}

void work(){
	for( R i = 1 ; i <= n ; i ++ ) ans [i] = 1e18 ; 
	dfs( 1 , 0 ) ;
	for( R i = 2 ; i <= n ; i ++ ) printf( "%.10Lf\n" , -1.0 * cal( i , las [i][0] ) ) ;
}

signed main(){
//	of() ;
	sc() ;
	work() ;
//	cf() ;
	return 0 ;
}
posted @ 2021-07-16 16:36  Soresen  阅读(71)  评论(0)    收藏  举报