D. Master of Data Structure
题意:给你一颗树,然后有m次操作,每次操作都会选择一条链进行操作,具体操作如题。
思路:我们发现m只有2000次,因此每次对一条链操作,该链至多只有2000个权值不同的节点,因此我们可以把权值相同的节点缩为一个点,这样至多只要更新2000个节点就行,那么我们离线对m次操作选取的节点建立一颗虚树,虚树的边维护两个信息,一个是两点之间有多少个节点,一个是两点之间的点权值,然后就暴力更新查询就搞定了
#include <bits/stdc++.h>
#define pi pair<int, long long>
#define mk make_pair
#define pb push_back
#define ll long long
using namespace std;
const int maxn = 5e5 + 10 ;
vector< int > G[ maxn] ;
pi W[ maxn] ;
int dep[ maxn] , f[ maxn] , vis[ maxn] , a[ maxn] ;
int anc[ maxn] [ 20 ] , id[ maxn] , S[ 6100 ] , cnt, cnt2, Top;
ll val[ maxn] ;
struct node {
int opt, u, v, k;
} q[ 2010 ] ;
void dfs ( int u, int fa, int rt) {
dep[ u] = dep[ fa] + 1 ;
anc[ u] [ 0 ] = fa;
for ( int i = 1 ; i < 20 ; i++ )
anc[ u] [ i] = anc[ anc[ u] [ i - 1 ] ] [ i - 1 ] ;
id[ u] = ++ cnt;
if ( vis[ u] )
a[ ++ cnt2] = u;
for ( auto v : G[ u] )
if ( v != fa)
dfs ( v, u, rt) ;
}
int LCA ( int u, int v) {
if ( dep[ u] < dep[ v] )
swap ( u, v) ;
for ( int i = 19 ; i >= 0 ; i-- )
if ( dep[ anc[ u] [ i] ] >= dep[ v] )
u = anc[ u] [ i] ;
if ( u == v)
return u;
for ( int i = 19 ; i >= 0 ; i-- )
if ( anc[ u] [ i] != anc[ v] [ i] )
u = anc[ u] [ i] , v = anc[ v] [ i] ;
return anc[ u] [ 0 ] ;
}
void work ( int x, int opt, int k, int tp, ll & res, ll & mx, ll & mn) {
if ( opt == 1 ) {
val[ x] + = k;
if ( tp)
W[ x] . second + = k;
}
else if ( opt == 2 ) {
val[ x] ^ = k;
if ( tp)
W[ x] . second ^ = k;
}
else if ( opt == 3 ) {
if ( val[ x] >= k)
val[ x] - = k;
if ( tp && W[ x] . second >= k)
W[ x] . second - = k;
}
else if ( opt == 4 ) {
res + = val[ x] ;
if ( tp)
res + = 1ll * W[ x] . first * W[ x] . second;
}
else if ( opt == 5 ) {
res ^ = val[ x] ;
if ( tp && W[ x] . first % 2 )
res ^ = W[ x] . second;
}
else if ( opt == 6 ) {
mx = max ( mx, val[ x] ) ;
mn = min ( mn, val[ x] ) ;
if ( tp && W[ x] . first) {
mx = max ( mx, W[ x] . second) ;
mn = min ( mn, W[ x] . second) ;
}
res = mx - mn;
}
else {
mn = min ( mn, abs ( val[ x] - 1ll * k) ) ;
if ( tp && W[ x] . first)
mn = min ( mn, abs ( W[ x] . second - 1ll * k) ) ;
res = mn;
}
}
void gao ( int opt, int x, int y, int k) {
ll res = 0 , mx = 0 , mn = 1e18 ;
while ( x != y) {
if ( dep[ x] < dep[ y] )
swap ( x, y) ;
work ( x, opt, k, 1 , res, mx, mn) ;
x = f[ x] ;
}
work ( x, opt, k, 0 , res, mx, mn) ;
if ( opt >= 4 )
printf ( "%lld\n" , res) ;
}
void add ( int u, int v) {
if ( dep[ u] < dep[ v] )
swap ( u, v) ;
f[ u] = v;
val[ u] = 0 ;
W[ u] = mk ( dep[ u] - dep[ v] - 1 , 0 ) ;
}
void insert ( int x) {
if ( Top == 1 ) {
S[ ++ Top] = x;
return ;
}
int lca = LCA ( x, S[ Top] ) ;
if ( lca == S[ Top] ) {
S[ ++ Top] = x;
return ;
}
while ( Top > 1 && id[ S[ Top - 1 ] ] >= id[ lca] )
add ( S[ Top - 1 ] , S[ Top] ) , Top-- ;
if ( lca != S[ Top] )
add ( lca, S[ Top] ) , S[ Top] = lca;
S[ ++ Top] = x;
}
void build ( ) {
S[ Top = 1 ] = 0 ;
for ( int i = 1 ; i <= cnt2; i++ )
insert ( a[ i] ) ;
while ( Top > 1 )
add ( S[ Top - 1 ] , S[ Top] ) , Top-- ;
}
int main ( ) {
int T;
scanf ( "%d" , & T) ;
while ( T-- ) {
int n, m, u, v;
cnt = cnt2 = 0 ;
scanf ( "%d%d" , & n, & m) ;
for ( int i = 1 ; i <= n; i++ )
G[ i] . clear ( ) , vis[ i] = 0 ;
for ( int i = 1 ; i < n; i++ ) {
scanf ( "%d%d" , & u, & v) ;
G[ u] . pb ( v) ;
G[ v] . pb ( u) ;
}
for ( int i = 1 ; i <= m; i++ ) {
scanf ( "%d%d%d" , & q[ i] . opt, & q[ i] . u, & q[ i] . v) ;
if ( q[ i] . opt <= 3 || q[ i] . opt >= 7 )
scanf ( "%d" , & q[ i] . k) ;
vis[ q[ i] . u] = vis[ q[ i] . v] = 1 ;
}
vis[ 1 ] = 1 ;
dfs ( 1 , 0 , 0 ) ;
build ( ) ;
for ( int i = 1 ; i <= m; i++ )
gao ( q[ i] . opt, q[ i] . u, q[ i] . v, q[ i] . k) ;
}
}