JZOJ4918. 最近公共祖先

题目大意

给定一棵 n 个节点的树,根节点是1,每个点有一个点权 vi 。初始所有点都是白点。
m 个操作:

  • 将一个点染为黑点
  • 询问一个点 u 找到除自己外的一个黑点 v 使得 u,v 的LCA的权值尽可能大,输出这个权值。

Data Constraint
n100000,m200000

题解

考虑单独计算每个点对其他点的贡献。
对于一个修改操作 x ,首先 x 显然会对子树内的所有点造成贡献,如果 x 子树内之前没有黑点,那么 x 还要对父亲的其他子树造成贡献。
所以线段树维护答案,做区间修改操作即可。

时间复杂度: O(nlogn)

SRC

#include
#include
#include
#include
#include
using namespace std ;

#define N 100000 + 10
struct Tree {
    int val , tag ;
} T[4*N] ;

bool Exist[N] ;
int Node[2*N] , Next[2*N] , Head[N] , tot ;
int W[N] , fa[N] , DFN[N] , R[N] ;
int n , m , Cnt , ret ;

void link( int u , int v ) {
    Node[++tot] = v ;
    Next[tot] = Head[u] ;
    Head[u] = tot ;
}

void DFS( int x ) {
    DFN[x] = R[x] = ++ Cnt ;
    for (int p = Head[x] ; p ; p = Next[p] ) {
        if ( Node[p] == fa[x] ) continue ;
        fa[Node[p]] = x ;
        DFS( Node[p] ) ;
        R[x] = R[Node[p]] ;
    }
}

void Update( int v ) {
    if ( T[v].tag <= 0 ) return ;
    int ls = v + v , rs = v + v + 1 ;
    T[ls].val = max( T[ls].val , T[v].tag ) ;
    T[rs].val = max( T[rs].val , T[v].tag ) ;
    T[ls].tag = max( T[ls].tag , T[v].tag ) ;
    T[rs].tag = max( T[rs].tag , T[v].tag ) ;
    T[v].tag = 0 ;
}

void Modify( int v , int l , int r , int x , int y , int value ) {
    if ( x > y ) return ;
    if ( l == x && r == y ) {
        T[v].val = max( T[v].val , value ) ;
        T[v].tag = max( T[v].tag , value ) ;
        return ;
    }
    Update( v ) ;
    int mid = (l + r) / 2 ;
    if ( y <= mid ) Modify( v + v , l , mid , x , y , value ) ;
    else if ( x > mid ) Modify( v + v + 1 , mid + 1 , r , x , y , value ) ;
    else {
        Modify( v + v , l , mid , x , mid , value ) ;
        Modify( v + v + 1 , mid + 1 , r , mid + 1 , y , value ) ;
    }
    T[v].val = max( T[v+v].val , T[v+v+1].val ) ;
}

void Search( int v , int l , int r , int x ) {
    if ( l == x && r == x ) {
        ret = T[v].val ;
        return ;
    }
    Update( v ) ;
    int mid = (l + r) / 2 ;
    if ( x <= mid ) Search( v + v , l , mid , x ) ;
    else Search( v + v + 1 , mid + 1 , r , x ) ;
    T[v].val = max( T[v+v].val , T[v+v+1].val ) ;
}

int main() {
    freopen( "lca.in" , "r" , stdin ) ;
    freopen( "lca.out" , "w" , stdout ) ;
    scanf( "%d%d" , &n , &m ) ;
    for (int i = 1 ; i <= n ; i ++ ) scanf( "%d" , &W[i] ) ;
    for (int i = 1 ; i < n ; i ++ ) {
        int u , v ;
        scanf( "%d%d" , &u , &v ) ;
        link( u , v ) ;
        link( v , u ) ;
    }
    DFS( 1 ) ;
    memset( T , -1 , sizeof(T) ) ;
    for (int i = 1 ; i <= m ; i ++ ) {
        char op[10] ;
        scanf( "%s" , op + 1 ) ;
        if ( op[1] == 'M' ) {
            int x ;
            scanf( "%d" , &x ) ;
            Modify( 1 , 1 , n , DFN[x] , R[x] , W[x] ) ;
            if ( Exist[x] ) continue ;
            Exist[x] = 1 ;
            while ( fa[x] ) {
                int y = fa[x] ;
                Modify( 1 , 1 , n , DFN[y] , DFN[x] - 1 , W[y] ) ;
                Modify( 1 , 1 , n , R[x] + 1 , R[y] , W[y] ) ;
                if ( Exist[y] ) break ;
                Exist[y] = 1 ;
                x = y ;
            }
        } else {
            int x ;
            scanf( "%d" , &x ) ;
            ret = -1 ;
            Search( 1 , 1 , n , DFN[x] ) ;
            printf( "%d\n" , ret ) ;
        }
    }
}

以上.

你可能感兴趣的:(线段树)