JZOJ4918. 最近公共祖先

来源:互联网 发布:js点击屏幕 隐藏div 编辑:程序博客网 时间:2024/04/30 00:28

题目大意

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

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

Data Constraint
n100000,m200000

题解

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

时间复杂度:O(nlogn)

SRC

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std ;#define N 100000 + 10struct 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 ) ;        }    }}

以上.

1 0