题目大意
给定一棵n个节点的树,根节点是1,每个点有一个点权
有m个操作:
- 将一个点染为黑点
- 询问一个点
u 找到除自己外的一个黑点v使得u,v 的LCA的权值尽可能大,输出这个权值。Data Constraint
n≤100000,m≤200000题解
考虑单独计算每个点对其他点的贡献。
对于一个修改操作x,首先x 显然会对子树内的所有点造成贡献,如果x子树内之前没有黑点,那么x 还要对父亲的其他子树造成贡献。
所以线段树维护答案,做区间修改操作即可。时间复杂度:O(nlogn)
SRC
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> 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 ) ; } } }以上.

这是一篇关于图论算法的博客,探讨了如何解决寻找最近公共祖先(LCA)并最大化权值的问题。在给定一棵n个节点的树中,存在m个操作,包括将节点染色和询问权值最大的LCA。通过线段树数据结构,可以实现O(nlogn)的时间复杂度来更新和查询贡献。

4363

被折叠的 条评论
为什么被折叠?



