题目链接
问题分析
一道比较标准的模板题。唯一需要考虑的是换根操作。
发现换根对链上的操作并没有影响,考虑对树上以\(u\)为根子树的影响。设原树上以\(u\)为根的子树是\(T\)。如果新的根在\(T\)的外部,那么以\(u\)为根的子树不变。如果新根就是\(u\),那么子树就是整棵树。否则,取原树中\(u\)的一个儿子\(v\),\(v\)包含新的根,那么新的以\(u\)为根的子树就是整棵树去掉原树中以\(v\)为根的子树。所以我们其实并不需要改变树的结构,只需要记录根节点位置就好。
参考程序
#include <bits/stdc++.h>
#define LL long long
using namespace std;const int Maxn = 100010;
struct edge {int To, Next;edge() {}edge( int _To, int _Next ) : To( _To ), Next( _Next ) {}
};
edge Edge[ Maxn << 1 ];
int Start[ Maxn ], Used;
int A[ Maxn ], N, M, Root, Cnt;
int Size[ Maxn ], Son[ Maxn ], Father[ Maxn ], Deep[ Maxn ], Top[ Maxn ], Ind[ Maxn ], Ref[ Maxn ], Max[ Maxn ];
LL Sum[ Maxn << 2 ], Tag[ Maxn << 2 ];inline void AddEdge( int x, int y ) {Edge[ ++Used ] = edge( y, Start[ x ] );Start[ x ] = Used;return;
}
void Dfs1( int Index, int Fa ) {Deep[ Index ] = Deep[ Fa ] + 1;Size[ Index ] = 1;Father[ Index ] = Fa;for( int T = Start[ Index ]; T; T = Edge[ T ].Next ) {Dfs1( Edge[ T ].To, Index );if( Size[ Edge[ T ].To ] > Size[ Son[ Index ] ] ) Son[ Index ] = Edge[ T ].To;Size[ Index ] += Size[ Edge[ T ].To ];}return;
}
void Dfs2( int Index ) {Ind[ Index ] = ++Cnt;Ref[ Cnt ] = Index;if( Son[ Index ] ) {Top[ Son[ Index ] ] = Top[ Index ];Dfs2( Son[ Index ] );}for( int T = Start[ Index ]; T; T = Edge[ T ].Next ) {if( Edge[ T ].To == Son[ Index ] ) continue;Top[ Edge[ T ].To ] = Edge[ T ].To;Dfs2( Edge[ T ].To );}Max[ Index ] = Cnt;return;
}
void Build( int Index, int Left, int Right ) {if( Left == Right ) {Sum[ Index ] = A[ Ref[ Left ] ];return;}int Mid = ( Left + Right ) >> 1;Build( Index << 1, Left, Mid );Build( Index << 1 | 1, Mid + 1, Right );Sum[ Index ] = Sum[ Index << 1 ] + Sum[ Index << 1 | 1 ];return;
}
void TagDown( int Index, int Left, int Right ) {if( Left == Right ) return;if( Tag[ Index ] == 0 ) return;int Mid = ( Left + Right ) >> 1;Tag[ Index << 1 ] += Tag[ Index ];Tag[ Index << 1 | 1 ] += Tag[ Index ];Sum[ Index << 1 ] += ( Mid - Left + 1 ) * Tag[ Index ];Sum[ Index << 1 | 1 ] += ( Right - Mid ) * Tag[ Index ];Tag[ Index ] = 0;return;
}
void Add( int Index, int Left, int Right, int L, int R, int K ) {if( L > R ) return;TagDown( Index, Left, Right );if( L <= Left && Right <= R ) {Sum[ Index ] += K * ( Right - Left + 1 );Tag[ Index ] += K;return;}int Mid = ( Left + Right ) >> 1;if( L <= Mid ) Add( Index << 1, Left, Mid, L, R, K );if( R > Mid ) Add( Index << 1 | 1, Mid + 1, Right, L, R, K );Sum[ Index ] = Sum[ Index << 1 ] + Sum[ Index << 1 | 1 ];return;
}
LL Query( int Index, int Left, int Right, int L, int R ) {if( L > R ) return 0;TagDown( Index, Left, Right );if( L <= Left && Right <= R ) return Sum[ Index ];LL Ans = 0; int Mid = ( Left + Right ) >> 1;if( L <= Mid ) Ans += Query( Index << 1, Left, Mid, L, R );if( R > Mid ) Ans += Query( Index << 1 | 1, Mid + 1, Right, L, R );return Ans;
}
void AddLink( int u, int v, int k ) {while( Top[ u ] != Top[ v ] ) {if( Deep[ Top[ u ] ] < Deep[ Top[ v ] ] ) swap( u, v );Add( 1, 1, N, Ind[ Top[ u ] ], Ind[ u ], k );u = Father[ Top[ u ] ];}if( Deep[ u ] > Deep[ v ] ) swap( u, v );Add( 1, 1, N, Ind[ u ], Ind[ v ], k );return;
}
int Get( int y, int x ) {int Last = 0;while( Top[ x ] != Top[ y ] ) {Last = Top[ x ];x = Father[ Top[ x ] ];}if( x == y ) return Last;return Son[ y ];
}
void AddSubTree( int u, int k ) {if( u == Root ) {Add( 1, 1, N, 1, N, k );return;}if( Ind[ Root ] < Ind[ u ] || Ind[ Root ] > Max[ u ] ) {Add( 1, 1, N, Ind[ u ], Max[ u ], k );return;}int T = Get( u, Root );Add( 1, 1, N, 1, Ind[ T ] - 1, k );Add( 1, 1, N, Max[ T ] + 1, N, k );return;
}
LL QueryLink( int u, int v ) {LL Ans = 0;while( Top[ u ] != Top[ v ] ) {if( Deep[ Top[ u ] ] < Deep[ Top[ v ] ] ) swap( u, v );Ans += Query( 1, 1, N, Ind[ Top[ u ] ], Ind[ u ] );u = Father[ Top[ u ] ];}if( Deep[ u ] > Deep[ v ] ) swap( u, v );Ans += Query( 1, 1, N, Ind[ u ], Ind[ v ] );return Ans;
}
LL QuerySubTree( int u ) {if( u == Root )return Query( 1, 1, N, 1, N );if( Ind[ Root ] < Ind[ u ] || Ind[ Root ] > Max[ u ] )return Query( 1, 1, N, Ind[ u ], Max[ u ] );int T = Get( u, Root );return Query( 1, 1, N, 1, Ind[ T ] - 1 ) + Query( 1, 1, N, Max[ T ] + 1, N );
}
int main() {scanf( "%d", &N );Root = 1;for( int i = 1; i <= N; ++i ) scanf( "%d", &A[ i ] ); for( int i = 1; i < N; ++i ) {int x; scanf( "%d", &x );AddEdge( x, i + 1 );}Dfs1( Root, 0 );Top[ Root ] = Root;Dfs2( Root );Build( 1, 1, N );scanf( "%d", &M );for( int i = 1; i <= M; ++i ) {int Opt; scanf( "%d", &Opt );if( Opt == 1 ) scanf( "%d", &Root );if( Opt == 2 ) {int x, y, k; scanf( "%d%d%d", &x, &y, &k );AddLink( x, y, k );}if( Opt == 3 ) {int x, k; scanf( "%d%d", &x, &k );AddSubTree( x, k );}if( Opt == 4 ) {int u, v; scanf( "%d%d", &u, &v );printf( "%lld\n", QueryLink( u, v ) );}if( Opt == 5 ) {int u; scanf( "%d", &u );printf( "%lld\n", QuerySubTree( u ) );}}return 0;
}