[BZOJ5210]-最大连通子块和-树剖+动态DP

说在前面

感觉自己理解的很不透彻
很多东西的定义想半天…
最后还是看着大师的代码才调过的…


题目

BZOJ5210传送门
大师博客传送门
看题可戳传送门


解法

这里并不准备写什么解法,大师博客写的其实挺清楚的…没看懂就多读几遍多想想

就这道题,me感觉需要把维护的东西想清楚…
重链上的信息直接用 线段树维护 ,实际的答案并没有存下来,需要Query得到

虚边的信息上传,上传的是整条链所代表的子树的信息。有一个点发生变化,贡献就会发生变化,就需要撤销掉之前的贡献,然后换上新的。因为贡献并没有存下来,所以需要通过 Query 得到

初始状态可以在树剖的时候顺便dp一发,然后把dp得到的信息,以一种合适的方式放到线段树上
或者也可以是把所有点初始为0,然后往空树里面一个一个赋值。当然这一步也是需要补全权值为0时的信息的,只不过省去了手动dp的步骤

反正要想清楚…


#include 
#include 
#include 
#include 
#include 
#include 
#define QL Query( nd->ch[0] , lf , mid , L , R ) 
#define QR Query( nd->ch[1] , mid+1,rg , L , R ) 
using namespace std ;

int N , M , val[200005] , head[200005] , tp ;
long long g[200005] , f[200005] ;
struct Path{
    int pre , to ;
} p[400005] ;

struct HEap{
    priority_queue<long long,vector<long long>,less<long long> > hp , del ;
    void insert( long long x ){ hp.push( x ) ; }
    void erase( long long x ){ del.push( x ) ; }
    long long top(){
        while( !del.empty() && hp.top() == del.top() )
            hp.pop() , del.pop() ;
        return hp.empty() ? 0 : hp.top() ;
    }
} hp[200005] ;

struct Node{
    Node *ch[2] ;
    long long Lmax , Rmax , mx , sum ;
    void update(){
        Lmax = max( ch[0]->Lmax , ch[0]->sum + ch[1]->Lmax ) ;
        Rmax = max( ch[0]->Rmax + ch[1]->sum , ch[1]->Rmax ) ;
        mx = max( ch[0]->Rmax + ch[1]->Lmax , max( ch[0]->mx , ch[1]->mx ) ) ;
        sum = ch[0]->sum + ch[1]->sum ;
    }
    friend Node Merge( Node L , Node R ){
        Node rt ;
        rt.Lmax = max( L.Lmax , L.sum + R.Lmax ) ;
        rt.Rmax = max( L.Rmax + R.sum , R.Rmax ) ;
        rt.mx = max( L.Rmax + R.Lmax , max( L.mx , R.mx ) ) ;
        rt.sum = L.sum + R.sum ; return rt ;
    }
} *root , w[400005] , *tw = w ;

void In( int t1 , int t2 ){
    p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
    p[++tp] = ( Path ){ head[t2] , t1 } ; head[t2] = tp ;
}

int dep[200005] , fa[200005] , son[200005] , siz[200005] ;
int in[200005] , top[200005] , arc[200005] , dfs_c , bot[200005] ;
void dfs1( int u ){
    for( int i = head[u] ; i ; i = p[i].pre ){
        int v = p[i].to ;
        if( v == fa[u] ) continue ;
        fa[v] = u , dep[v] = dep[u] + 1 ;
        dfs1( v ) , siz[u] += siz[v] ;
        if( siz[ son[u] ] < siz[v] ) son[u] = v ;
    } siz[u] ++ ;
}

long long dfs2( int u , int topp ){
    long long now = 0 ;
    in[u] = ++dfs_c , arc[ dfs_c ] = u , top[u] = topp ;
    if( son[u] ) now = dfs2( son[u] , topp ) , bot[u] = bot[ son[u] ] ;
    else bot[u] = u ;

    g[u] = val[u] ;
    for( int i = head[u] ; i ; i = p[i].pre ){
        int v = p[i].to ;
        if( v == fa[u] || v == son[u] ) continue ;
        hp[u].insert( dfs2( v , v ) ) , g[u] += f[v] ;
    } f[u] = max( 0ll , g[u] + f[ son[u] ] ) , now = max( now , max( f[u] , hp[u].top() ) ) ;
    return now ;
}

Node *build( int lf , int rg ){
    Node *nd = ++tw ;
    if( lf == rg ){
        int u = arc[lf] ; nd->sum = g[u] ;
        nd->Lmax = nd->Rmax = max( 0ll , g[u] ) ;
        nd->mx = max( nd->Lmax , hp[u].top() ) ;
        return nd ;
    } int mid = ( lf + rg ) >> 1 ;
    nd->ch[0] = build( lf , mid ) ;
    nd->ch[1] = build( mid+1,rg ) ;
    nd->update() ; return nd ;
}

void Modify( Node *nd , int lf , int rg , int pos ){
    if( lf == rg ){
        int u = arc[lf] ; nd->sum = g[u] ;
        nd->Lmax = nd->Rmax = max( 0ll , g[u] ) ;
        nd->mx = max( nd->Lmax , hp[u].top() ) ; return ;
    } int mid = ( lf + rg ) >> 1 ;
    if( mid >= pos ) Modify( nd->ch[0] , lf , mid , pos ) ;
    else Modify( nd->ch[1] , mid+1,rg , pos ) ;
    nd->update() ;
}

Node Query( Node *nd , int lf , int rg , int L , int R ){
    if( L <= lf && rg <= R ) return *nd ;
    int mid = ( lf + rg ) >> 1 ;
    if( R <= mid ) return QL ;
    if( L > mid ) return QR ;
    return Merge( QL , QR ) ;
}

void Modify( int u , long long delta ){
    Node now , pre , ttt ; bool flag = false ;
    while( u ){
        ttt = Query( root , 1 , N , in[ top[u] ] , in[ bot[u] ] ) ;
        if( flag ) hp[u].erase( pre .mx ) , hp[u].insert( now.mx ) ;
        pre = ttt , flag = 1 ;
        g[u] += delta , Modify( root , 1 , N , in[u] ) ;
        now = Query( root , 1 , N , in[ top[u] ] , in[ bot[u] ] ) ;
        delta = now.Lmax - f[ top[u] ] , f[ top[u] ] = now.Lmax ;
        u = fa[ top[u] ] ;
    }
}

long long Query( int u ){
    Node ans = Query( root , 1 , N , in[u] , in[ bot[u] ] ) ;
    return ans.mx ;
}

void preWork(){
    dfs1( 1 ) ; dfs2( 1 , 1 ) ;
    root = build( 1 , N ) ;
}

void solve(){
    char opt[10] ;
    for( int i = 1 , x , y ; i <= M ; i ++ ){
        scanf( "%s%d" , opt , &x ) ;
        if( opt[0] == 'M' ){
            scanf( "%d" , &y ) ;
            Modify( x , y - val[x] ) , val[x] = y ;
        } else printf( "%lld\n" , Query( x ) ) ;
    }
}

int main(){
    scanf( "%d%d" , &N , &M ) ;
    for( int i = 1 ; i <= N ; i ++ )
        scanf( "%d" , &val[i] ) ;
    for( int i = 1 , u , v ; i < N ; i ++ )
        scanf( "%d%d" , &u , &v ) , In( u , v ) ;
    preWork() ; solve() ;
}

你可能感兴趣的:(线段树,动态dp)