这个题没有李超树的写法吗

P3195 [HNOI2008] 玩具装箱

~~码风可能比较鬼畜~~
by 吾名有灵 @ 2021-09-14 23:05:29


其实这题李超线段树写法会爆空间,所以如果不是数据水李超树是过不了的(理论H要开成 `5e11` ,但是会炸空间,我开`1e9` 水过的)。 给一份代码供参考 ```c++ #include <bits/stdc++.h> #define int long long #define R register int #define scanf Ruusupuu = scanf #define freopen rsp_5u = freopen #define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) int Ruusupuu ; FILE * rsp_5u ; using namespace std ; typedef long long L ; typedef double D ; const int H = 1e9 ; const int Inf = 1e18 + 98 ; const int N = 5e4 + 10 ; 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 ^ 48 ) , ch = getchar() ; return fg ? -w : w ; } int n , ll , root , znt , c [N] , k [N] , f [N] ; void sc(){ n = read() , ll = read() ; for( R i = 1 ; i <= n ; i ++ ) c [i] = read() + c [i - 1] , k [i] = c [i] + i ; } struct LINE{ int k , b ; inline int f( int x ){ return k * x + b ; } LINE(){} LINE( int _k , int _b ){ k = _k , b = _b ; } } ; inline double met( LINE a , LINE b ){ return ( 1.0 * ( b.b - a.b ) ) / ( 1.0 * ( a.k - b.k ) ) ; } struct T{ int ls , rs ; LINE data ; } t [N << 8] ; void upd( int &x , int l , int r , LINE w ){ if( !x ) x = ++ znt ; if( l == r ){ if( t [x].data.f( l ) > w.f( l ) ) t [x].data = w ; return ; } if( t [x].data.f( l ) >= w.f( l ) && t [x].data.f( r ) >= w.f( r ) ) return swap( t [x].data , w ) , void() ; if( t [x].data.f( l ) <= w.f( l ) && t [x].data.f( r ) <= w.f( r ) ) return ; double mid = ( l + r ) * 0.5 , meet = met( t [x].data , w ) ; int mmid = ( l + r ) >> 1 ; assert( meet <= r && meet >= l ) ; if( meet <= mid ){ if( t [x].data.f( r ) >= w.f( r ) ) swap( t [x].data , w ) ; upd( t [x].ls , l , mmid , w ) ; } else{ if( t [x].data.f( l ) >= w.f( l ) ) swap( t [x].data , w ) ; upd( t [x].rs , mmid + 1 , r , w ) ; } } int ask( int x , int l , int r , int pos ){ if( !x ) return 0 ; if( l == r ) return t [x].data.f( pos ) ; int mid = ( l + r ) >> 1 ; if( pos <= mid ) return min( t [x].data.f( pos ) , ask( t [x].ls , l , mid , pos ) ) ; else return min( t [x].data.f( pos ) , ask( t [x].rs , mid + 1 , r , pos ) ) ; } void work(){ for( R i = 1 ; i <= n ; i ++ ){ f [i] = ( ll + 1 ) * ( ll + 1 ) + k [i] * k [i] - 2 * k [i] * ( ll + 1 ) + ask( root , 1 , H , k [i] ) , assert( k [i] <= H ) ; upd( root , 1 , H , LINE( -2 * k [i] , f [i] + 2 * k [i] * ( ll + 1 ) + k [i] * k [i] ) ) , assert( k [i] <= H ) ; } printf( "%lld\n" , f [n] ) ; } signed main(){ // freopen("fake.in","r",stdin),freopen("fake.out","w",stdout); sc() ; work() ; return 0 ; } ```
by YksKuusiTAlv @ 2021-10-08 16:26:08


~~我马蜂和您一样鬼畜~~
by YksKuusiTAlv @ 2021-10-08 16:26:59


@[YksKuusiTAlv](/user/365246) 数据不水也行吧,这个可以以1~n为李超树区间,可以设一个$w[i]$表示$sum[i] + i - L + 1$然后计算每个区间的左右端点就不用带入l,r而代入$w[l],w[r]$就行了,而且就算$5e11$也爆不了吧,动态开点李超维护直线的时候空间是O(直线个数)的吧
by Fyrsta_ @ 2022-10-16 11:40:39


|