| #include<iostream> |
| #include<cstdio> |
| #include<cmath> |
| #include<algorithm> |
| #include<cstring> |
| |
| #define lid id << 1 |
| #define rid id << 1 | 1 |
| |
| using namespace std; |
| |
| long long n, m, r, rank_[5211314], new_id; |
| |
| long long cnt, head[5211314], w[5211314]; |
| |
| |
| struct Chain_Forward_Star { |
| long long next; |
| long long to; |
| }pic[5211314]; |
| |
| struct Heavy_Light_Decompostion { |
| long long Father; |
| long long Deep; |
| long long Size; |
| long long Heavy_Son; |
| long long Top; |
| long long Id; |
| }HL_tree[5211314]; |
| |
| |
| struct Segment_tree { |
| long long l, r; |
| long long lazy, sum, maxn; |
| }Seg_tree[5211314]; |
| |
| inline long long read() { |
| long long x = 0, f = 1; |
| char ch = getchar(); |
| while ( ch < '0' || ch > '9' ) { |
| if ( ch == '-' ) f = -1; |
| ch = getchar(); |
| } |
| while ( ch >= '0' && ch <= '9' ) { |
| x = ( x << 1 ) + ( x << 3 ) + ( ch -'0' ); |
| ch = getchar(); |
| } |
| return x * f; |
| } |
| |
| void print( long long x ) { |
| if ( x < 0 ) putchar( '-' ), x *= -1; |
| if ( x > 9 ) print( x / 10 ); |
| putchar( x % 10 + '0' ); |
| return; |
| } |
| |
| inline void add_edge( long long v1 , long long v2 ) { |
| ++ cnt; |
| pic[cnt].next = head[v1]; |
| head[v1] = cnt; |
| pic[cnt].to = v2; |
| return; |
| } |
| |
| inline void pushdown( long long id ) { |
| if ( Seg_tree[id].lazy ) { |
| long long temp = Seg_tree[id].lazy; |
| Seg_tree[lid].lazy += temp; |
| Seg_tree[rid].lazy += temp; |
| Seg_tree[lid].sum += temp * ( Seg_tree[lid].r - Seg_tree[lid].l + 1 ); |
| Seg_tree[rid].sum += temp * ( Seg_tree[rid].r - Seg_tree[rid].l + 1 ); |
| Seg_tree[lid].maxn += temp; |
| Seg_tree[rid].maxn += temp; |
| Seg_tree[id].lazy = 0; |
| } |
| } |
| |
| inline void pushup( long long id ) { |
| Seg_tree[id].sum = Seg_tree[lid].sum + Seg_tree[rid].sum; |
| Seg_tree[id].maxn = max( Seg_tree[lid].maxn , Seg_tree[rid].maxn ); |
| return; |
| } |
| |
| void build_tree( long long id , long long l , long long r ) { |
| Seg_tree[id].l = l; |
| Seg_tree[id].r = r; |
| long long mid = ( l + r ) >> 1; |
| if ( l == r ) { |
| Seg_tree[id].sum = Seg_tree[id].maxn = w[rank_[l]]; |
| |
| return; |
| } |
| build_tree( lid , l , mid ); |
| build_tree( rid , mid + 1 , r ); |
| pushup( id ); |
| return; |
| } |
| |
| void update( long long id , long long l , long long r , long long add_num ) { |
| if ( Seg_tree[id].l >= l && Seg_tree[id].r <= r ) { |
| Seg_tree[id].sum += add_num * ( Seg_tree[id].r - Seg_tree[id].l + 1 ); |
| Seg_tree[id].maxn += add_num; |
| Seg_tree[id].lazy += add_num; |
| return; |
| } |
| pushdown( id ); |
| long long mid = ( Seg_tree[id].l + Seg_tree[id].r ) >> 1; |
| if ( l <= mid ) update( lid , l , r , add_num ); |
| if ( r > mid ) update( rid , l , r , add_num ); |
| pushup( id ); |
| return; |
| } |
| |
| long long segtree_query_sum( long long id , long long l , long long r ) { |
| if ( Seg_tree[id].l >= l && Seg_tree[id].r <= r ) { |
| return Seg_tree[id].sum; |
| } |
| pushdown( id ); |
| long long ans = 0; |
| long long mid = ( Seg_tree[id].l + Seg_tree[id].r ) >> 1; |
| if ( l <= mid ) ans += segtree_query_sum( lid , l , r ); |
| if ( r > mid ) ans += segtree_query_sum( rid , l , r ); |
| return ans; |
| } |
| |
| long long segtree_query_max( long long id , long long l , long long r ) { |
| if ( Seg_tree[id].l >= l && Seg_tree[id].r <= r ) { |
| return Seg_tree[id].maxn; |
| } |
| pushdown( id ); |
| long long ans = -521131400000; |
| long long mid = ( Seg_tree[id].l + Seg_tree[id].r ) >> 1; |
| if ( l <= mid ) ans = max( ans , segtree_query_max( lid , l , r ) ); |
| if ( r > mid ) ans = max( ans , segtree_query_max( rid , l , r ) ); |
| return ans; |
| } |
| |
| inline long long query_sum( long long x , long long y ) { |
| long long ans = 0; |
| long long left, right; |
| while ( HL_tree[x].Top != HL_tree[y].Top ) { |
| |
| if ( HL_tree[HL_tree[x].Top].Deep < HL_tree[HL_tree[y].Top].Deep ) { |
| swap( x , y ); |
| |
| } |
| left = HL_tree[HL_tree[x].Top].Id; |
| right = HL_tree[x].Id; |
| |
| ans = ans + segtree_query_sum( 1 , left , right ); |
| |
| x = HL_tree[HL_tree[x].Top].Father; |
| |
| } |
| |
| if ( HL_tree[x].Deep > HL_tree[y].Deep ) { |
| swap( x , y ); |
| |
| } |
| left = HL_tree[x].Id; |
| right = HL_tree[y].Id; |
| ans += segtree_query_sum( 1 , left , right ); |
| return ans; |
| } |
| |
| inline long long query_max( long long x , long long y ) { |
| long long ans = -521131400000; |
| long long left, right; |
| while ( HL_tree[x].Top != HL_tree[y].Top ) { |
| if ( HL_tree[HL_tree[x].Top].Deep < HL_tree[HL_tree[y].Top].Deep ) { |
| swap( x , y ); |
| } |
| left = HL_tree[HL_tree[x].Top].Id; |
| right = HL_tree[x].Id; |
| ans = max( ans , segtree_query_max( 1 , left , right ) ); |
| x = HL_tree[HL_tree[x].Top].Father; |
| } |
| if ( HL_tree[x].Deep > HL_tree[y].Deep ) { |
| swap( x , y ); |
| } |
| left = HL_tree[x].Id; |
| right = HL_tree[y].Id; |
| ans = max( ans , segtree_query_max( 1 , left , right ) ); |
| return ans; |
| } |
| |
| inline void HL_update( long long x , long long y ,long long add_num ) { |
| long long left, right; |
| while ( HL_tree[x].Top != HL_tree[y].Top ) { |
| if ( HL_tree[HL_tree[x].Top].Deep < HL_tree[HL_tree[y].Top].Deep ) { |
| swap( x , y ); |
| } |
| left = HL_tree[HL_tree[x].Top].Id; |
| right = HL_tree[x].Id; |
| update( 1 , left , right , add_num ); |
| x = HL_tree[HL_tree[x].Top].Father; |
| } |
| if ( HL_tree[x].Deep > HL_tree[y].Deep ) { |
| swap( x , y ); |
| } |
| left = HL_tree[x].Id; |
| right = HL_tree[y].Id; |
| update( 1 , left , right , add_num ); |
| return; |
| } |
| |
| void DFS_1( long long now , long long fa ) { |
| |
| HL_tree[now].Father = fa; |
| HL_tree[now].Deep = HL_tree[fa].Deep + 1; |
| HL_tree[now].Size = 1; |
| for (long long i = head[now], v; i != 0; i = pic[i].next) { |
| |
| v = pic[i].to; |
| if ( v != fa ) { |
| |
| DFS_1( v , now ); |
| HL_tree[now].Size += HL_tree[v].Size; |
| if ( HL_tree[v].Size > HL_tree[HL_tree[now].Heavy_Son].Size ) { |
| HL_tree[now].Heavy_Son = v; |
| } |
| } |
| } |
| return; |
| } |
| |
| void DFS_2( long long now , long long top ) { |
| |
| HL_tree[now].Top = top; |
| HL_tree[now].Id = ++ new_id; |
| rank_[new_id] = now; |
| if ( HL_tree[now].Heavy_Son ) DFS_2( HL_tree[now].Heavy_Son , top ); |
| |
| for (long long i = head[now], v; i != 0; i = pic[i].next) { |
| v = pic[i].to; |
| if ( v != HL_tree[now].Father && v != HL_tree[now].Heavy_Son ) { |
| |
| |
| DFS_2( v , v ); |
| |
| } |
| } |
| return; |
| } |
| |
| int main() |
| { |
| n = read(); |
| m = read(); |
| r = read(); |
| for (int i = 1; i <= n; ++i) { |
| w[i] = read(); |
| } |
| for (int i = 1, a, b; i <= n - 1; ++i) { |
| a = read(); |
| b = read(); |
| add_edge( a , b ); |
| add_edge( b , a ); |
| } |
| DFS_1( r , 0 ); |
| DFS_2( r , r ); |
| build_tree( 1 , 1 , n ); |
| for (long long i = 1, x, y, z, p; i <= m; ++i) { |
| p = read(); |
| if ( p == 1 ) { |
| |
| x = read(); |
| y = read(); |
| z = read(); |
| HL_update( x , y , z ); |
| } |
| else if ( p == 2 ) { |
| |
| x = read(); |
| y = read(); |
| print( query_sum( x , y ) ); |
| putchar( '\n' ); |
| } |
| else if ( p == 3 ) { |
| |
| x = read(); |
| z = read(); |
| update( 1 , HL_tree[x].Id , HL_tree[x].Id + HL_tree[x].Size - 1 , z ); |
| |
| } |
| else if ( p == 4 ) { |
| |
| x = read(); |
| print( segtree_query_sum( 1 , HL_tree[x].Id , HL_tree[x].Id + HL_tree[x].Size - 1 ) ); |
| putchar( '\n' ); |
| } |
| } |
| return 0; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!