拖了超级久的树链剖分终于真正写了一次。
个人感觉就是,代码长只是因为函数有点多,总体思想和代码都很水,除了两遍dfs外基本就是裸的线段树了。
代码真的很水啊。。。。
个人速记(因为我太弱了):
第一遍dfs:size,son,dep
第二遍dfs:origin,tree,top
我觉得最值得注意的细节就是 在操作中要分清用的是原树中的点编号还是线段树中的点编号
#include <bits/stdc++.h>
using namespace std;
#define f(i, x, y) for (int i = x; i <= y; ++ i)
#define ff(i, x, y) for (int i = x; i < y; ++ i)
#define pb push_back
const int N = 30010;
const int T = N * 4;
int fa[N], size[N], son[N], dep[N];
int ori[N], tr[N], top[N];
int Max[T], sum[T], tip[N];
vector<int> a[N], tmp[N];
int n, m, val[N], tot, Q, x, y;
int SUM, MAX;
inline void get(int &k){
int p = 0, t = 1; char x = getchar();
while ( x < '0' || x > '9' ) {
if ( x == '-' ) t = -1;
x = getchar();
}
while ( x >='0' && x <= '9' ) p = p * 10 + x - '0', x = getchar();
k = p * t;
return ;
}
inline void dfs1(int t, int depth){
dep[t] = depth; size[t] = 1;
ff(i, 0, tmp[t].size())
if ( ! dep[ tmp[t][i] ] ) {
int v = tmp[t][i];
dfs1( v, depth + 1);
size[t] += size[v];
if ( size[ son[t] ] < size[v] ) son[t] = v;
fa[v] = t;
a[t].pb(v);
}
}
inline void dfs2(int t, int anc){
tr[t] = ++ tot ; ori[tot] = t; top[t] = anc;
if ( ! son[t] ) return ;
dfs2( son[t], anc );
ff(i, 0, a[t].size())
if ( a[t][i] != son[t] )
dfs2( a[t][i], a[t][i] );
}
inline void build(int p, int l, int r){ //以下全是线段树的操作
if ( l == r ){
Max[p] = sum[p] = val[ ori[l] ];
return ;
}
int mid = ( l + r ) >> 1;
build( p + p + 1 , l , mid );
build( p + p + 2 , mid + 1 , r );
Max[p] = max( Max[p+p+1], Max[p+p+2] );
sum[p] = sum[p+p+1] + sum[p+p+2];
return ;
}
void update(int p, int l, int r, int t, int x){
if ( t < l || r < t ) return ;
if ( l == r ){
if ( l == t ) sum[p] = Max[p] = x;
return ;
}
int mid = ( l + r ) >> 1;
update( p + p + 1, l, mid, t, x);
update( p + p + 2, mid + 1, r, t, x);
sum[p] = sum[p+p+1] + sum[p+p+2];
Max[p] = max( Max[p+p+1], Max[p+p+2] );
return ;
}
void Query(int p, int l, int r, int L, int R){
if ( l > r ) return ;
if ( R < l || r < L ) return ;
if ( L <= l && r <= R ){
MAX = max( MAX , Max[p] );
SUM += sum[p];
return ;
}
int mid = ( l + r ) >> 1;
Query( p + p + 1, l, mid, L, R );
Query( p + p + 2, mid + 1, r, L, R );
}
void query(){ // 将查询最大值和求和合并在一起
SUM = 0; MAX = -1e5;
int f1 = top[x] , f2 = top[y];
while ( f1 != f2 ) {
if ( dep[f1] < dep[f2] ) swap( f1 , f2 ), swap( x , y );
Query( 0, 1, n, tr[f1], tr[x]) ;//注意代入线段树查询的是tr[x]!!!
x = fa[f1] ; f1 = top[x];
}
if ( dep[x] > dep[y] ) swap( x , y );// 同一条链上 深度小的节点在线段树中的编号也小
Query( 0 , 1 , n , tr[x] , tr[y] );
}
int main(){
get(n);
ff(i, 1, n) {
get( x ), get( y );
tmp[x].pb( y ), tmp[y].pb( x );
}
f(i, 1, n) get( val[i] );
dfs1( 1 , 1 );
dfs2( 1 , 1 );
build( 0, 1, n );
get( Q );
while ( Q -- ){
char x1 = getchar(), x2 = getchar();
get(x);
get(y);
if ( x1 == 'C' ) {
update(0, 1, n, tr[x], y);
val[x] = y;
continue;
}
query();
if ( x2 == 'S' ) printf("%d\n", SUM);
else printf("%d\n", MAX);
}
return 0;
}