【HDU】5759 Gardener Bo【线段树+lca+分类讨论】

题目链接:Gardener Bo

分情况处理add操作即可。

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <algorithm>
using namespace std ;

typedef unsigned int UI ;
typedef pair < int , int > pii ;

#define clr( a , x ) memset ( a , x , sizeof a )
#define root 1 , 1 , n
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r

const int MAXN = 300005 ;
const int MAXE = 300005 ;

struct Edge {
    int v , n ;
    Edge () {}
    Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;

Edge E[MAXE] ;
int H[MAXN] , cntE ;
int pre[MAXN] ;
int siz[MAXN] ;
int top[MAXN] ;
int dep[MAXN] ;
int pos[MAXN] ;
int out[MAXN] ;
int son[MAXN] ;
int cnt[MAXN] ;
int num[MAXN] ;
int tree_idx ;
int n , q ;
UI sum[MAXN << 2] ;
UI cnt_siz[MAXN] ;
UI add[MAXN] ;
UI w[MAXN] ;
UI f[MAXN] ;

void init () {
    cntE = 0 ;
    tree_idx = 0 ;
    clr ( H , -1 ) ;
    clr ( sum , 0 ) ;
}

void addedge ( int u , int v ) {
    E[cntE] = Edge ( v , H[u] ) ;
    H[u] = cntE ++ ;
}

void dfs ( int u ) {
    siz[u] = 1 ;
    son[u] = 0 ;
    cnt[u] = 0 ;
    num[u] = 0 ;
    add[u] = 0 ;
    cnt_siz[u] = 0 ;
    for ( int i = H[u] ; ~i ; i = E[i].n ) {
        int v = E[i].v ;
        dep[v] = dep[u] + 1 ;
        dfs ( v ) ;
        cnt[u] ++ ;
        cnt_siz[u] += ( UI ) ( cnt[v] + 1 ) * siz[v] ;
        num[u] += cnt[v] + 1 ;
        siz[u] += siz[v] ;
        if ( siz[v] > siz[son[u]] ) son[u] = v ;
    }
    f[u] = w[u] * ( siz[u] + 1 ) ;
    for ( int i = H[u] ; ~i ; i = E[i].n ) {
        int v = E[i].v ;
        w[u] += w[v] ;
        f[u] += w[v] * ( siz[u] - siz[v] ) ;
    }
}

void rebuild ( int u , int top_element ) {
    top[u] = top_element ;
    pos[u] = ++ tree_idx ;
    if ( son[u] ) rebuild ( son[u] , top_element ) ;
    for ( int i = H[u] ; ~i ; i = E[i].n ) {
        int v = E[i].v ;
        if ( v != son[u] ) rebuild ( v , v ) ;
    }
    out[u] = tree_idx ;
    return ;
}

void Update ( int x , UI w ) {
    while ( top[x] != top[1] ) {
        int v = top[x] , u = pre[v] ;
        f[u] += w * ( siz[u] - siz[v] ) ;
        x = u ;
    }
}

void update ( int x , UI v , int o , int l , int r ) {
    sum[o] += v ;
    if ( l == r ) return ;
    int m = l + r >> 1 ;
    if ( x <= m ) update ( x , v , lson ) ;
    else update ( x , v , rson ) ;
}

UI query ( int L , int R , int o , int l , int r ) {
    if ( L <= l && r <= R ) return sum[o] ;
    int m = l + r >> 1 ;
    if ( R <= m ) return query ( L , R , lson ) ;
    if ( m <  L ) return query ( L , R , rson ) ;
    return query ( L , R , lson ) + query ( L , R , rson ) ;
}

void solve () {
    init () ;
    for ( int i = 2 ; i <= n ; ++ i ) {
        scanf ( "%d" , &pre[i] ) ;
        addedge ( pre[i] , i ) ;
    }
    for ( int i = 1 ; i <= n ; ++ i ) {
        scanf ( "%u" , &w[i] ) ;
    }
    dfs ( 1 ) ;
    rebuild ( 1 , 1 ) ;
    while ( q -- ) {
        int op , u ;
        UI x ;
        scanf ( "%d%d" , &op , &u ) ;
        if ( op == 1 ) {
            scanf ( "%u" , &x ) ;
            add[u] += x ;
            Update ( u , x * ( num[u] + 1 ) ) ;
            update ( pos[u] , x * ( num[u] + 1 ) , root ) ;
        } else {
            UI ans = f[u] ;
            int fa = pre[u] ;
            ans += add[u] * siz[u] * num[u] + add[u] * ( siz[u] + 1 ) - add[u] * cnt_siz[u] ;
            if ( fa ) {
                int ga = pre[fa] ;
                ans += add[fa] * cnt[u] * siz[u] + add[fa] * 2 ;
                if ( ga ) ans += add[ga] * ( siz[u] + 1 ) ;
            }
            if ( son[u] ) ans += ( siz[u] - siz[son[u]] ) * query ( pos[son[u]] , out[son[u]] , root ) ;
            printf ( "%u\n" , ans ) ;
        }
    }
}

int main () {
    while ( ~scanf ( "%d%d" , &n , &q ) ) solve () ;
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值