Tree chain split (from entry to be buried.)

Pre-knowledge: tree line, before the chain to the star, LCA, DFS order

Chain normal operation tree split:
1.x -> 2.x modify the path y -> x subtree 3. For query submissions 4. For subtree query path x y.

Usually there root change operation. Tree section also can do LCA.

DFS chain split tree has two two DFS is to a tree into a sequence. You can then use the data to maintain the structure.

The first request for a DFS \ (FA \) (ancestor node) \ (size \) (subtree size) \ (Son \) (weight son) \ (D \) (depth) of the
weight refers to a son \ ( size \) greater son nodes.
The second request for DFS \ (Top \) (top strand of this point) \ (ID \) (number) and other assignment. But heavy son first DFS.

const int N = 1e5 + 10 ;
struct node { int v , nxt ; } ;
node e[N << 1] ;
int head[N] , cnt = 0 ;
inline void Add(int u , int v) { e[++ cnt].v = v ; e[cnt].nxt = head[u] ; head[u] = cnt ; }
int size[N] , son[N] , d[N] ;
inline void Dfs1(int u) { size[u] = 1 ;
  for(register int i = head[u] ; i ; i = e[i].nxt) {
    int v = e[i].v ; if(v == fa[u]) continue ; // 防止无限递归。
    d[v] = d[u] + 1 , fa[v] = u ,  // 记录深度 以及父亲节点
Dfs1(v) ; size[u] += size[v] ; //算出子树大小
    if(size[v] > size[son[u]]) son[u] = v ; //得出u 的 重儿子是 son[u]
  }
}
int top[N] , id[N] , tot = 0 ;
inline void Dfs2(int u , int tp) { top[u] = tp , id[u] = ++ tot ;
  if(! son[u]) return ; Dfs2(son[u] , tp) ;
  for(register int i = head[u] ; i ; i = e[i].nxt) { int v = e[i].v ;
    if(v ^ fa[u] && v ^ son[u]) Dfs2(v , v) ;
  }
}

Even if this is a general board of no value ... (assigned according to the numbering engage in a practice on it below speak.)

[Template] tree chain split

#include <bits/stdc++.h>
using namespace std ;
inline int read() { register int res = 0 ; register char c ;
#define gc c = getchar()
    while(isspace(gc)) ;
    while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(gc)) ;
    return res ;
}
int n , m , r , p ;
const int N = 1000000 + 5 ;
struct E{ int v ;int nxt ; } ;
E edge[N << 1] ;
int a[N] ; int fa[N] ; int w[N] ; int id[N] ; int son[N] ;
int cnt = 0 ; int head[N] ; int Add[N << 2] , laz[N << 2] ;
int dep[N] , siz[N] , t[N] ;
inline void Add_Edge(register int u , register int v) { edge[++ cnt].v = v ; edge[cnt].nxt = head[u] ; head[u] = cnt ; return ; }//建边。
#define l(x) x << 1
#define r(x) x << 1 | 1
inline void Push_down(register int x , register int len) {
    laz[l(x)] += laz[x] ; laz[r(x)] += laz[x] ;
    Add[l(x)] += laz[x] * (len - (len >> 1)) ; Add[r(x)] += laz[x] * (len >> 1) ;
    Add[l(x)] %= p ; Add[r(x)] %= p ;
    laz[x] = 0 ; return ;
}
inline void Build(register int l , register int r , register int rt) {//建树
    if(l == r) { Add[rt] = a[l] ;  return ; }
    register int mid = l + r >> 1 ;
    Build(l , mid , l(rt)) ; Build(mid + 1 , r , r(rt)) ;
    Add[rt] = (Add[l(rt)] + Add[r(rt)]) % p ;
}
inline void Update(register int a , register int b , register int l  , register int r , register int rt , register int k) {//正常的线段树操作
    if(a <= l and r <= b) { laz[rt] += k ; Add[rt] += k * (r - l + 1) ; }
    else {
        if(laz[rt]) Push_down(rt , r - l + 1) ;
        register int mid = l + r >> 1 ;
        if(a <= mid) Update(a , b , l , mid , l(rt) , k) ;
        if(b > mid) Update(a , b , mid + 1 , r , r(rt) , k) ;
        Add[rt] = (Add[l(rt)] + Add[r(rt)]) % p ;
    }
}
int res = 0 ;
inline void query(register int a , register int b , register int  l , register int r , register int rt) {
    if(a <= l and r <= b) { res = (res + Add[rt]) % p ; return ; }
    else {
        if(laz[rt]) Push_down(rt , r - l + 1) ;
        register int mid = l + r >> 1 ;
        if(a <= mid) query(a , b , l , mid , l(rt)) ;
        if(b > mid) query(a , b , mid + 1 , r , r(rt)) ;
    }
}
inline int Query(register int a , register int b , register int l , register int r , register int rt) {//正常的线段树操作
    res = 0 ; query(a , b , l , r , rt) ;
    return res % p ;
}
inline void Upd_Range(register int x , register int y , register int k) {//链上修改
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
         Update(id[t[x]] , id[x] , 1 , n , 1 , k) ;
         x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    Update(id[x] , id[y] , 1 , n , 1 , k) ;
}
inline int Query_Range(register int x , register int y) {//链上查询
    int ans = 0 ;
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
        ans += Query(id[t[x]] , id[x] , 1 , n , 1) ;
        x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    ans += Query(id[x] , id[y] , 1 , n , 1) ;
    return ans % p ;
}
inline int Qson(register int x) { return Query(id[x] , id[x] + siz[x] - 1 , 1 , n , 1) ; } // 子树查询。
inline void Updson(register int x , register int k) { Update(id[x] , id[x] + siz[x] - 1 , 1 , n , 1 , k) ; return ; }
inline void Dfs1(register int x , register int f , register int deep) {
    dep[x] = deep ; fa[x] = f ; siz[x] = 1 ;
    int max_son = -1 ;
    for(register int i = head[x] ; i ; i = edge[i].nxt) {
        register int v = edge[i].v ;
        if(v == f) continue ;
        Dfs1(v , x , deep + 1) ;siz[x] += siz[v] ;
        if(siz[v] > max_son) max_son = siz[v] , son[x] = v ;
    }
}
int tot = 0 ;
inline void Dfs2(register int x , register int tf) {
    id[x] = ++ tot ; a[tot] = w[x] ; t[x] = tf ; // a 数组重新赋值
    if(! son[x]) return ;
    Dfs2(son[x] , tf) ;
    for(register int i = head[x] ; i ; i = edge[i].nxt) {
        int v = edge[i].v ;
        if(v == fa[x] or v == son[x]) continue ;
        Dfs2(v , v) ;
    }
}
signed main() {
    n = read() ; m = read() ; r = read() ; p = read() ;
    for(register int i = 1 ; i <= n ; i ++) w[i] = read() ;
    for(register int i = 1 ; i <= n - 1 ; i ++) {
        int u = read() , v = read() ;
        Add_Edge(u , v) ;
        Add_Edge(v , u) ;
    }
    Dfs1(r , 0 , 1) ; Dfs2(r , r) ; Build(1 , n , 1) ;
    for( ; m -- ; ) {
        register int opt = read() ;
        if(opt == 1) {
            register int x = read() , y = read() , k = read() ;
            Upd_Range(x , y , k % p) ;
        }
        if(opt == 2) {
            register int x = read() , y = read() ;
            printf("%d\n" , Query_Range(x , y)) ;
        }
        if(opt == 3) {
            register int x = read() , y = read() ;
            Updson(x , y) ;
        }
        if(opt == 4) { printf("%d\n" , Qson(read())) ; }
    }
    return 0 ;
}

[USACO11DEC] grass planting Grass Planting

Modify a single point of inquiry on the chain.
For this subject is to be modified edge weights.
Here's a tip is passed to point at the right side and then the value of the top point ignored. (Easy to prove that this is possible.)
Then perform basic operations on it.

#include<bits/stdc++.h>
using namespace std ;
#define int long long
#define fi first
#define se second
#define pb push_back
inline int read() {
    register int x = 0 , f = 1 ;
    register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
}
template < typename T > inline bool cmax(T & x , T y) {
    return x < y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cmin(T & x , T y) {
    return x > y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cabs(T & x) {
    return x > 0 ? 1 : (x = - x) , 0 ;
}
inline int QP(int x , int y , int Mod) {
    int ans = 1 ;
    for( ; y ; y >>= 1 , x = (x * x) % Mod)
        if(y & 1) ans = (ans * x) % Mod ;
    return ans ;
}
int n , m ;
struct node {
  int v , nxt ;
} ;
const int N = 1e5 + 10 ;
node e[N << 1] ;
int head[N] , cnt = 0 ;
inline void Add(int u , int v) {
  e[++ cnt].v = v ;
  e[cnt].nxt = head[u] ;
  head[u] = cnt ;
  return ;
}
int fa[N] ;
int top[N] ;
int d[N] ;
int size[N] ;
int son[N] ;
int id[N] , idx = 0 ;
int a[N] ;
int sum[N << 2] ;
inline void build(int l , int r , int rt) {
  if(l == r) {
    sum[rt] = a[l] ;
    return ;
  }
  int mid = l + r >> 1 ;
  build(l , mid , rt << 1) ;
  build(mid + 1 , r , rt << 1 | 1) ;
}
int tag[N << 2] ;
inline void Push_down(int rt , int l , int r) {
  if(! tag[rt]) return ;
  tag[rt << 1] += tag[rt] ;
  tag[rt << 1 | 1] += tag[rt] ;
  int mid = l + r >> 1 ;
  sum[rt << 1] += tag[rt] * (mid - l + 1) ;
  sum[rt << 1 | 1] += tag[rt] * (r - mid) ;
  tag[rt] = 0 ;
  return ;
}
inline void Update(int a , int b , int l , int r , int rt) {
  if(a <= l && r <= b) { sum[rt] += (r - l + 1) ; tag[rt] ++ ; return ; }
  Push_down(rt , l , r) ;
  int mid = l + r >> 1 ;
  if(a <= mid) Update(a , b , l , mid , rt << 1) ;
  if(b > mid) Update(a , b , mid + 1 , r , rt << 1 | 1) ;
  sum[rt] = sum[rt << 1] + sum[rt << 1 | 1] ;
}
inline int Query(int a , int b , int l , int r , int rt) {
  if(a <= l && r <= b) return sum[rt] ;
  Push_down(rt , l , r) ;
  int mid = l + r >> 1 , ans = 0 ;
  if(a <= mid) ans += Query(a , b , l , mid , rt << 1) ;
  if(b > mid) ans += Query(a , b , mid + 1 , r , rt << 1 | 1) ;
  return ans ;
}
inline void Dfs(int u) {
  size[u] = 1 ;
  for(register int i = head[u] ; i ; i = e[i].nxt) {
    int v = e[i].v ;
    if(v == fa[u]) continue ;
    fa[v] = u ;
    d[v] = d[u] + 1 ;
    Dfs(v) ;
    size[u] += size[v] ;
    if(size[son[u]] < size[v]) son[u] = v ;
  }
}
inline void Dfs2(int u , int t) {
  top[u] = t ;
  a[idx] = 0 ;
  id[u] = ++ idx ;
  if(! son[u]) return ;
  Dfs2(son[u] , t) ;
  for(register int i = head[u] ; i ; i = e[i].nxt) {
    int v = e[i].v ;
    if(v ^ fa[u] && v ^ son[u]) Dfs2(v , v) ;
  }
}
inline void Change(int x , int y) {
  int fx = top[x] ;
  int fy = top[y] ;
  while(fx ^ fy) {
    if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
    Update(id[fx] , id[x] , 1 , n , 1) ;
    x = fa[fx] ;
    fx = top[x] ;
  }
  if(d[x] > d[y]) swap(x , y) ;
  Update(id[x] + 1 , id[y] , 1 , n , 1) ;
}
inline int Query_Range(int x , int y) {
  int ans = 0 ;
  int fx = top[x] ;
  int fy = top[y] ;
  while(fx ^ fy) {
    if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
    ans += Query(id[fx] , id[x] , 1 , n , 1) ;
    x = fa[fx] ;
    fx = top[x] ;
  }
  if(d[x] > d[y]) swap(x , y) ;
  ans += Query(id[x] + 1 , id[y] , 1 , n , 1) ;
  return ans ;
}
signed main() {
  n = read() ; m = read() ;
  for(register int i = 1 ; i <= n - 1 ; i ++) {
    int u = read() , v = read() ;
    Add(u , v) ;
    Add(v , u) ;
  }
  Dfs(1) ;
  Dfs2(1 , 0) ;
  build(1 , n , 1) ;
  for(register int i = 1 ; i <= m ; i ++) {
    register char c = getchar() ;
    while(c != 'P' && c != 'Q') c = getchar() ;
    int u = read() , v = read() ;
    if(c == 'P') Change(u , v) ;
    else printf("%lld\n" , Query_Range(u , v)) ;
  }
    return 0 ;
}

[USACO15DEC] Maximum Flow Max Flow

Tree cross is seeking LCA to this problem, for example.
This problem is the need to put pressure on the two point two points plus 1 then the two points \ (LCA \) lose 1 point because this also need to add 1 so we can put this in the 1 \ (fa_LCA \ ) lose
so recursively to the bottom and then obviously have to add up the tree weights

#include<bits/stdc++.h>
using namespace std ;
#define int long long
#define fi first
#define se second
#define pb push_back
inline int read() {
    register int x = 0 , f = 1 ;
    register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
}
template < typename T > inline bool cmax(T & x , T y) {
    return x < y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cmin(T & x , T y) {
    return x > y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cabs(T & x) {
    return x > 0 ? 1 : (x = - x) , 0 ;
}
inline int QP(int x , int y , int Mod) {
    int ans = 1 ;
    for( ; y ; y >>= 1 , x = (x * x) % Mod)
        if(y & 1) ans = (ans * x) % Mod ;
    return ans ;
}
int n ;
struct node {
  int v , nxt ;
} ;
const int N = 50000 + 5 ;
node e[N << 1] ;
int head[N] , cnt = 0 ;
inline void Add(int u , int v) {
  e[++ cnt].v = v ;
  e[cnt].nxt = head[u] ;
  head[u] = cnt ;
  return ;
}
int fa[N] ;
int size[N] ;
int son[N] ;
int top[N] ;
int d[N] ;
inline void Dfs(int u) {
  size[u] = 1 ;
  for(register int i = head[u] ; i ; i = e[i].nxt) {
    int v = e[i].v ;
    if(v == fa[u]) continue ;
    fa[v] = u ;
    d[v] = d[u] + 1 ;
    Dfs(v) ;
    size[u] += size[v];
    if(size[v] > size[son[u]]) son[u] = v ;
  }
}
inline void Dfs2(int u , int t) {
  top[u] = t ;
  if(! son[u]) return ;
  Dfs2(son[u] , t) ;
  for(register int i = head[u] ; i ; i = e[i].nxt) {
    int v = e[i].v ;
    if(v ^ fa[u] && v ^ son[u]) Dfs2(v , v) ;
  }
}
inline int Lca(int x , int y) {//树剖求LCA
  int fx = top[x] , fy = top[y] ;
  while(fx ^ fy) {
    if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
    x = fa[fx] ;
    fx = top[x] ;
  }
  if(d[x] > d[y]) swap(x , y) ;
  return x ;
}
int ad[N] ;
int ans = 0 ;
inline void Getans(int u , int father) { // 不断往下找 然后更新答案
  for(register int i = head[u] ; i ; i = e[i].nxt) {
    int v = e[i].v ;
    if(v == father) continue ;
    Getans(v , u) ;
    ad[u] += ad[v] ;
  }
  ans = max(ans , ad[u]) ;
}
signed main() {
  n = read() ; int k = read() ;
  for(register int i = 1 ; i <= n - 1 ;  i ++) {
    int u = read() , v = read() ;
    Add(u , v) ;
    Add(v , u) ;
  }
  Dfs(1) ;
  Dfs2(1 , 0) ;
  for(register int i = 1 ; i <= k ; i ++) {
    int u = read() , v = read() ;
    int lca = Lca(u , v) ;
    ad[u] ++ ;
    ad[v] ++ ;
    ad[lca] -- ;
    ad[fa[lca]] -- ;
  }// 树上差分
  Getans(1 , 0) ;
  printf("%lld" , ans) ;
    return 0 ;
}

[HEOI2016 / TJOI2016] tree

Tips title
this problem is the mainstream, but does not seem to practice two points in the chain this?
The chain-half to note is reversed. .

#include<bits/stdc++.h>
using namespace std ;
#define int long long
#define fi first
#define se second
#define pb push_back
inline int read() {
    register int x = 0 , f = 1 ;
    register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
}
template < typename T > inline bool cmax(T & x , T y) {
    return x < y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cmin(T & x , T y) {
    return x > y ? (x = y) , 1 : 0 ;
}
template < typename T > inline bool cabs(T & x) {
    return x > 0 ? 1 : (x = - x) , 0 ;
}
inline int QP(int x , int y , int Mod) {
    int ans = 1 ;
    for( ; y ; y >>= 1 , x = (x * x) % Mod)
        if(y & 1) ans = (ans * x) % Mod ;
    return ans ;
}
int n , m ;
struct node {
    int v , nxt ;
} ;
const int N = 1e5 + 10 ;
node e[N << 1] ;
int head[N] , cnt = 0 ;
inline void Add(int u , int v) { e[++ cnt].v = v , e[cnt].nxt = head[u] , head[u] = cnt ; }
int fa[N] , size[N] , son[N] , d[N] ;
inline void Dfs(int u) { size[u] = 1 ; for(register int i = head[u] ; i ; i = e[i].nxt) {
        int v = e[i].v ; if(v == fa[u]) continue ;
        d[v] = d[u] + 1 , fa[v] = u , Dfs(v) , size[u] += size[v] ;
        if(size[v] > size[son[u]]) son[u] = v ;
    }
}
int top[N] , id[N] , idx = 0 , f[N] ;
inline void Dfs2(int u , int t) { id[u] = ++ idx , top[u] = t , f[idx] = u ;
    if(! son[u]) return ; Dfs2(son[u] , t) ;
    for(register int i = head[u] ; i ; i = e[i].nxt) {
        int v = e[i].v ; if(v ^ fa[u] && v ^ son[u]) Dfs2(v , v) ;
    }
}
int sum[N << 2] ;
inline void build(int l , int r , int rt){
    if(l == r) { sum[rt] = 0 ; return ; }
    int mid = l + r >> 1 ; build(l , mid , rt << 1) , build(mid + 1 , r , rt << 1 | 1) ;
}
inline void upd(int x , int l , int r , int rt) {
    if(l == r) { sum[rt] = 1 ; return ; }
    int mid = l + r >> 1 ;
    if(x <= mid) upd(x , l , mid , rt << 1) ; else upd(x , mid + 1 , r , rt << 1 | 1) ;
    sum[rt] = sum[rt << 1] + sum[rt << 1 | 1] ;
}
inline int query(int a , int b , int l , int r , int rt) {
    if(a <= l && r <= b) { return sum[rt] ; }
    int mid = l + r >> 1 , ans = 0 ;
    if(a <= mid) ans += query(a , b , l , mid , rt << 1) ;
    if(b > mid) ans += query(a , b ,  mid + 1 , r , rt << 1 | 1) ;
    return ans ;
}
inline int chk(int l , int r) { // 二分找答案
    if(l == r) return l ;
    int mid = l + r >> 1 ;
    if(query(mid + 1 , r , 1 , n , 1)) return chk(mid + 1 , r) ; // 反过来。
    else return chk(l , mid) ;
}
inline int Find(int x , int y = 1) { // 求答案 因为最近的点一定是在 1 ~ x 的这条路径上。
    int fx = top[x] , fy = top[y] ;
    while(fx ^ fy) {
        if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
        int q = query(id[fx] , id[x] , 1 , n , 1) ;
        if(q) return chk(id[fx] , id[x]) ;
        else { x = fa[fx] , fx = top[x] ; continue ; }
    }
    if(d[x] > d[y]) swap(x , y) ;
    return chk(id[x] , id[y]) ;
}
signed main() {
    n = read() ; m = read() ;
    for(register int i = 1 ; i <= n - 1 ; i ++) { int u = read() , v = read() ; Add(u , v) , Add(v , u) ;}
    Dfs(1) , Dfs2(1 , 0) , build(1 , n , 1) ;
    for(register int i = 1 ; i <= m ; i ++) {
        register char c = getchar() ;
        while(c != 'C' && c != 'Q') c = getchar() ;
        int x = read() ;
        if(c == 'C') upd(id[x] , 1 , n , 1) ;
        if(c == 'Q') printf("%lld\n" , f[Find(x)]) ;
    }
    return 0 ;
}

[National Team] tourism
sol

//Isaunoya
#include<bits/stdc++.h>
using namespace std ;
inline int read() {
    register int x = 0 ;
    register int f = 1 ;
    register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
}
int st[105] ;
template < typename T > inline void write(T x , char c = '\n') {
    int tp = 0 ;
    if(x == 0) return (void) puts("0") ;
    if(x < 0) putchar('-') , x = -x ;
    for( ; x ; x /= 10) st[++ tp] = x % 10 ;
    for( ; tp ; tp --) putchar(st[tp] + '0') ;
    putchar(c) ;
}
//#define Online_Judge
//#define int long long
#define swap(x , y) x ^= y ^= x ^= y
int n ;
const static int N = 200000 + 5 ;
int a[N] ;
namespace SegTree {
    struct Node {
        int mn ; // the min
        int mx ; // the max
        int add ; // the sum
        int lazy ; // the sign
    };
    Node t[N << 2] ;
    inline void Push_down(int rt) {
        if(t[rt].lazy) {
            t[rt << 1].add = - t[rt << 1].add ;
            t[rt << 1 | 1].add = - t[rt << 1 | 1].add ;
            t[rt << 1].lazy ^= 1 ;
            t[rt << 1 | 1].lazy ^= 1 ;
            swap(t[rt << 1].mx , t[rt << 1].mn) ;
            swap(t[rt << 1 | 1].mx , t[rt << 1 | 1].mn) ;
            t[rt << 1].mx = - t[rt << 1].mx ;
            t[rt << 1].mn = - t[rt << 1].mn ;
            t[rt << 1 | 1].mx = - t[rt << 1 | 1].mx ;
            t[rt << 1 | 1].mn = - t[rt << 1 | 1].mn ;
            t[rt].lazy = 0 ;
        }
        return ;
    }
    //==============================================push_down
    inline void Push_Up(int rt) {
        t[rt].add = t[rt << 1].add + t[rt << 1 | 1].add ;
        t[rt].mx = max(t[rt << 1].mx , t[rt << 1 | 1].mx) ;
        t[rt].mn = min(t[rt << 1].mn , t[rt << 1 | 1].mn) ;
        return ;
    }
    //==============================================push_up
    inline void build(int l , int r , int rt) {
        if(l == r) {
            t[rt].add = t[rt].mn = t[rt].mx = a[l] ;
            return ;
        }
        int mid = l + r >> 1 ;
        build(l , mid , rt << 1) ;
        build(mid + 1 , r , rt << 1 | 1) ;
        Push_Up(rt) ;
    }
    //==============================================build
    inline void Add(int x , int l , int r , int rt , int val) {
        if(l == r) {
            t[rt].add = t[rt].mn = t[rt].mx = val ;
            return ;
        }
        int mid = l + r >> 1 ;
        Push_down(rt) ;
        if(x <= mid) Add(x , l , mid , rt << 1 , val) ;
        else Add(x , mid + 1 , r , rt << 1 | 1 , val) ;
        Push_Up(rt) ;
    }
    //==============================================change x - > val
    inline void Change(int a , int b , int l , int r , int rt) {
        if(a > r || b < l) return ;
        if(a <= l && r <= b) {
            t[rt].add = - t[rt].add ;
            t[rt].lazy ^= 1 ;
            swap(t[rt].mx , t[rt].mn) ;
            t[rt].mx = - t[rt].mx ;
            t[rt].mn = - t[rt].mn ;
            return ;
        }
        int mid = l + r >> 1 ;
        Push_down(rt) ;
        Change(a , b , l , mid , rt << 1) ;
        Change(a , b , mid + 1 , r , rt << 1 | 1) ;
        Push_Up(rt) ;
    }
    //===============================================change x - > -x
    inline int Sum(int a , int b , int l , int r , int rt) {
        if(a > r || b < l) return 0 ;
        if(a <= l && r <= b) return t[rt].add ;
        int mid = l + r >> 1 ;
        Push_down(rt) ;
        int ans = 0 ;
        ans += Sum(a , b , l , mid , rt << 1 ) ;
        ans += Sum(a , b , mid + 1 , r , rt << 1 | 1) ;
        Push_Up(rt) ;
        return ans ;
    }
    //====================================================== a - > b sum
    inline int Min(int L , int R , int l , int r , int rt) {
        if(L > r || R < l) return INT_MAX ;
        if(L <= l && r <= R) return t[rt].mn ;
        int ans = INT_MAX ;
        int mid = l + r >> 1 ;
        Push_down(rt) ;
        if(L <= mid) ans = min(ans , Min(L , R , l , mid , rt << 1)) ;
        if(R > mid) ans = min(ans , Min(L , R, mid + 1 , r , rt << 1 | 1)) ;
        Push_Up(rt) ;
        return ans ;
    }
    //====================================================== a - > b min
    inline int Max(int L , int R , int l , int r , int rt) {
        if(L > r || R < l) return INT_MIN ;
        if(L <= l && r <= R) return t[rt].mx ;
        int ans = INT_MIN ;
        int mid = l + r >> 1 ;
        Push_down(rt) ;
        if(L <= mid) ans = max(ans , Max(L , R , l , mid , rt << 1)) ;
        if(R > mid) ans = max(ans , Max(L , R, mid + 1 , r , rt << 1 | 1)) ;
        Push_Up(rt) ;
        return ans ;
    }
    //====================================================== a - > b max
}
//===========================================================SegTree
namespace SLPF {
    struct node {
        int v ;
        int nxt ;
        int w ;
    };
    int fa[N] ; int id[N] ; int son[N] ;
    int size[N] ; int d[N] ; int top[N] ;
    int fst[N] ;
    node e[N << 1] ;
    int tot = 0 ;
    int head[N] ; int cnt = 0 ;
    inline void Add_Edge(int u , int v , int w) {
        e[++ cnt].v = v ;
        e[cnt].nxt = head[u] ;
        e[cnt].w = w ;
        head[u] = cnt ;
        return ;
    }
    inline void Dfs1(int u) {
        size[u] = 1 ;
        for(register int i = head[u] ; i ; i = e[i].nxt) {
            int v = e[i].v ;
            if(v ^ fa[u]) {
                d[v] = d[u] + 1 ;
                fa[v] = u ;
                fst[v] = e[i].w ;
                Dfs1(v) ;
                size[u] += size[v] ;
                if(size[v] > size[son[u]]) son[u] = v ;
            }
        }
    }
    inline void Dfs2(int u , int t) {
        id[u] = ++ tot ;
        top[u] = t ;
        a[tot] = fst[u] ;
        if(son[u]) Dfs2(son[u] , t) ;
        for(register int i = head[u] ; i ; i = e[i].nxt) {
            int v = e[i].v ;
            if(v ^ fa[u] && v ^ son[u]) Dfs2(v , v) ;
        }
    }
    //========================================================Dfs1 && Dfs2

    inline void Change_Range(int x , int y) {
        int fx = top[x] ;
        int fy = top[y] ;
        while(fx ^ fy) {
            if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
            SegTree::Change(id[fx] , id[x] , 1 , tot , 1) ;
            x = fa[fx] ;
            fx = top[x] ;
        }
        if(id[x] > id[y]) swap(x , y) ;
        SegTree::Change(id[x] + 1 , id[y] , 1 , tot , 1) ;
    }
    inline int Query_Sum(int x , int y) {
        int fx = top[x] ;
        int fy = top[y] ;
        int ans = 0 ;
        while(fx ^ fy) {
            if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
            ans += SegTree::Sum(id[fx] , id[x] , 1 , tot , 1) ;
            x = fa[fx] ;
            fx = top[x] ;
        }
        if(id[x] > id[y]) swap(x , y) ;
        ans += SegTree::Sum(id[x] + 1 , id[y] , 1 , tot , 1) ;
        return ans ;
    }
    inline int Query_Min(int x , int y) {
        int fx = top[x] ;
        int fy = top[y] ;
        int ans = INT_MAX ;
        while(fx ^ fy) {
            if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
            ans = min(ans , SegTree::Min(id[fx] , id[x] , 1 , tot , 1)) ;
            x = fa[fx] ;
            fx = top[x] ;
        }
        if(id[x] > id[y]) swap(x , y) ;
        ans = min(ans , SegTree::Min(id[x] + 1 , id[y] , 1 , tot , 1)) ;
        return ans ;
    }
    inline int Query_Max(int x , int y) {
        int fx = top[x] ;
        int fy = top[y] ;
        int ans = INT_MIN ;
        while(fx ^ fy) {
            if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
            ans = max(ans , SegTree::Max(id[fx] , id[x] , 1 , tot , 1)) ;
            x = fa[fx] ;
            fx = top[x] ;
        }
        if(id[x] > id[y]) swap(x , y) ;
        ans = max(ans , SegTree::Max(id[x] + 1 , id[y] , 1 , tot , 1)) ;
        return ans ;
    }
}
using namespace SLPF ;
inline int getopt() {
    string s = "" ;
    register char c = getchar() ;
    while(isspace(c)) c = getchar() ;
    while(! isspace(c)) {
        s += c ;
        c = getchar() ;
    }
    if(s == "C") return 0 ;
    if(s == "N") return 1 ;
    if(s == "SUM") return 2 ;
    if(s == "MAX") return 3 ;
    if(s == "MIN") return 4 ;
}
signed main() {
#ifdef Online_Judge
    freopen("testdata.in" , "r" , stdin) ;
    freopen("testdata2.out" , "w" , stdout) ;
#endif
    n = read() ;
    for(register int i = 1 ; i <= n - 1 ; i ++) {
        int u = read() , v = read() , w = read() ;
        u ++ , v ++ ;
        Add_Edge(u , v , w) ;
        Add_Edge(v , u , w) ;
    }
    Dfs1(1) ;
    Dfs2(1 , 0) ;
    SegTree::build(1 , n , 1) ;
    for(register int t = read() ; t -- ; ) {
        int opt = getopt() ;
//      write(opt) ;
        if(opt == 0) {
            int x = read() , y = read() ;
            x ++ ;
            SegTree::Add(id[x] , 1 , n , 1 , y) ;
        }
        if(opt == 1) {
            int x = read() , y = read() ;
            x ++ , y ++ ;
            Change_Range(x , y) ;
        }
        if(opt == 2) {
            int x = read() , y = read() ;
            x ++ , y ++ ;
            write(Query_Sum(x , y)) ;
        }
        if(opt == 3) {
            int x = read() , y = read() ;
            x ++ , y ++ ;
            write(Query_Max(x , y)) ;
        }
        if(opt == 4) {
            int x = read() , y = read() ;
            x ++ , y  ++ ;
            write(Query_Min(x , y)) ;
        }
    }
    return 0 ;
}

[ZJOI2008] tree statistics

Similar to the template title. .

//Isaunoya
#include <bits/stdc++.h>
using namespace std ;
inline int read() { register int x = 0 ; register int f = 1 ; register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
} int st[105] ;
template < typename T > inline void write(T x , char c = '\n') { int tp = 0 ;
    if(x == 0) return (void) puts("0") ;
    if(x < 0) putchar('-') , x = -x ;
    for( ; x ; x /= 10) st[++ tp] = x % 10 ;
    for( ; tp ; tp --) putchar(st[tp] + '0') ;
    putchar(c) ;
}
int n , m , r , p ;
const int N = 10000000 + 5 ;
struct E{ int v ;int nxt ; } ;
E edge[N << 1] ;
int a[N] ; int fa[N] ; int w[N] ; int id[N] ; int son[N] ;
int cnt = 0 ; int head[N] ; int Add[N << 2] , laz[N << 2] ;
int mx[N << 2] ;
int dep[N] , siz[N] , t[N] ;
inline void Add_Edge(register int u , register int v) { edge[++ cnt].v = v ; edge[cnt].nxt = head[u] ; head[u] = cnt ; return ; }
#define l(x) x << 1
#define r(x) x << 1 | 1
inline void Push_down(register int x , register int len) {
    laz[l(x)] += laz[x] ; laz[r(x)] += laz[x] ;
    Add[l(x)] += laz[x] * (len - (len >> 1)) ; Add[r(x)] += laz[x] * (len >> 1) ;
    Add[l(x)] %= p ; Add[r(x)] %= p ;
    laz[x] = 0 ; return ;
}
inline void Build(register int l , register int r , register int rt) {
    if(l == r) { mx[rt] = Add[rt] = a[l] ;  return ; }
    register int mid = l + r >> 1 ;
    Build(l , mid , l(rt)) ; Build(mid + 1 , r , r(rt)) ;
    Add[rt] = (Add[l(rt)] + Add[r(rt)])  ;
    mx[rt] = max(mx[rt << 1] , mx[rt << 1 | 1]) ;
}
inline void Update(register int a , register int b , register int l  , register int r , register int rt , register int k) {
    if(a <= l and r <= b) { laz[rt] += k ; Add[rt] += k * (r - l + 1) ; }
    else {
        if(laz[rt]) Push_down(rt , r - l + 1) ;
        register int mid = l + r >> 1 ;
        if(a <= mid) Update(a , b , l , mid , l(rt) , k) ;
        if(b > mid) Update(a , b , mid + 1 , r , r(rt) , k) ;
        Add[rt] = (Add[l(rt)] + Add[r(rt)])  ;
        mx[rt] = max(mx[rt << 1] , mx[rt << 1 | 1]) ;
    }
}
inline void upd(int x , int l , int r , int rt , int v) {
    if(l == r) {
        mx[rt] = Add[rt] = v ;
        return ;
    }
    int mid = l + r >> 1 ;
    if(x <= mid) upd(x , l , mid , rt << 1 , v) ;
    else upd(x , mid + 1 , r , rt << 1 | 1 , v) ;
    Add[rt] = (Add[l(rt)] + Add[r(rt)])  ;
    mx[rt] = max(mx[rt << 1] , mx[rt << 1 | 1]) ;
}
int res = 0 ;
inline void query(register int a , register int b , register int  l , register int r , register int rt) {
    if(a <= l and r <= b) { res = (res + Add[rt])  ; return ; }
    else {
        if(laz[rt]) Push_down(rt , r - l + 1) ;
        register int mid = l + r >> 1 ;
        if(a <= mid) query(a , b , l , mid , l(rt)) ;
        if(b > mid) query(a , b , mid + 1 , r , r(rt)) ;
    }
}
inline int Query(register int a , register int b , register int l , register int r , register int rt) {
    res = 0 ; query(a , b , l , r , rt) ;
    return res  ;
}
inline int Query_Max(int a , int b , int l , int r , int rt) {
    if(a <= l && r <= b) return mx[rt] ;
    int mid = l + r >> 1 ;
    int ans = INT_MIN ;
    if(a <= mid) ans = max(ans , Query_Max(a , b , l , mid , rt << 1)) ;
    if(b > mid) ans = max(ans , Query_Max(a , b , mid + 1 , r , rt << 1 | 1)) ;
    return ans ;
}
inline void Upd_Range(register int x , register int y , register int k) {
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
         Update(id[t[x]] , id[x] , 1 , n , 1 , k) ;
         x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    Update(id[x] , id[y] , 1 , n , 1 , k) ;
}
inline int Query_Range(register int x , register int y) {
    int ans = 0 ;
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
        ans += Query(id[t[x]] , id[x] , 1 , n , 1) ;
        x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    ans += Query(id[x] , id[y] , 1 , n , 1) ;
    return ans  ;
}
inline int Query_Max_Range(register int x , register int y) {
    int ans = INT_MIN ;
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
        ans = max(ans , Query_Max(id[t[x]] , id[x] , 1 , n , 1)) ;
        x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    ans = max(ans , Query_Max(id[x] , id[y] , 1 , n , 1)) ;
    return ans  ;
}
inline int Qson(register int x) { return Query(id[x] , id[x] + siz[x] - 1 , 1 , n , 1) ; }
inline void Updson(register int x , register int k) { Update(id[x] , id[x] + siz[x] - 1 , 1 , n , 1 , k) ; return ; }
inline void Dfs1(register int x , register int f , register int deep) {
    dep[x] = deep ; fa[x] = f ; siz[x] = 1 ;
    int max_son = -1 ;
    for(register int i = head[x] ; i ; i = edge[i].nxt) {
        register int v = edge[i].v ;
        if(v == f) continue ;
        Dfs1(v , x , deep + 1) ;siz[x] += siz[v] ;
        if(siz[v] > max_son) max_son = siz[v] , son[x] = v ;
    }
}
int tot = 0 ;
inline void Dfs2(register int x , register int tf) {
    id[x] = ++ tot ; a[tot] = w[x] ; t[x] = tf ;
    if(! son[x]) return ;
    Dfs2(son[x] , tf) ;
    for(register int i = head[x] ; i ; i = edge[i].nxt) {
        int v = edge[i].v ;
        if(v == fa[x] or v == son[x]) continue ;
        Dfs2(v , v) ;
    }
}
inline int getopt() {
    string s = "" ; register char c = getchar() ;
    while(isspace(c)) c = getchar() ;
    while(! isspace(c)) {
        s += c ;
        c = getchar() ;
    }
    if(s == "CHANGE") return 0 ;
    if(s == "QMAX") return 1 ;
    if(s == "QSUM") return 2 ; 
}
signed main() {
    n = read() ; 
    for(register int i = 1 ; i <= n - 1 ; i ++) {
        int u = read() , v = read() ;
        Add_Edge(u , v) ;
        Add_Edge(v , u) ;
    }for(register int i = 1 ; i <= n ; i ++) w[i] = read() ;
    m = read() ; r = 1 ;
    Dfs1(r , 0 , 1) ; Dfs2(r , r) ; Build(1 , n , 1) ;
    for( ; m -- ; ) {
        int opt = getopt() ;
//        cout  << opt ;
        int u = read() , v = read() ;
        if(opt == 0) {
            upd(id[u] , 1 , n , 1 , v) ;
        }
        if(opt == 1) {
            write(Query_Max_Range(u , v)) ;
        }
        if(opt == 2) {
            write(Query_Range(u , v)) ;
        }
    }
    return 0 ;
}

Above all with the sequence segment tree maintenance in fact, not have to use tree cross the line as long as the tree data structure can be
for example if not ODT ODT what you will of course have nothing better ODT can use the card out of the tree line but the problem is not always easy in the trees card out.

[NOI2015] package manager
because there are dependencies between software

  • Per-install the software on the root node to put the entire path becomes software x 1
  • Similarly uninstall the software each time put x and its sub-tree value becomes 0
//Isaunoya
#include<bits/stdc++.h>
using namespace std ;
inline int read() { register int x = 0 ; register int f = 1 ; register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
} int st[105] ;
template < typename T > inline void write(T x , char c = '\n') { int tp = 0 ;
    if(x == 0) return (void) puts("0") ;
    if(x < 0) putchar('-') , x = -x ;
    for( ; x ; x /= 10) st[++ tp] = x % 10 ;
    for( ; tp ; tp --) putchar(st[tp] + '0') ;
    putchar(c) ;
}
//#define Online_Judge

struct node {
    int l ; int r ;
    mutable int val ;
    bool operator < (const node & x) const {
        return l < x.l ;
    }
};
set < node > s ;

#define slt set < node > :: iterator
inline slt Split(int pos) {
    slt it = s.lower_bound((node) {pos}) ;
    if(it != s.end() && it -> l == pos) return it ;
    -- it ;
    int l = it -> l ;
    int r = it -> r ;
    int val = it -> val ;
    s.erase(it) ;
    s.insert({l , pos - 1 , val}) ;
    return s.insert({pos , r , val}).first ;
}
inline int Assign(int l , int r , int val) {
    slt it2 = Split(r + 1) ;
    slt it1 = Split(l) ;
    int sum = 0 ;
    int sum2 = (r - l + 1) * val  ;
    for(slt it = it1 ; it != it2 ; it ++) sum += (it -> r - it -> l + 1) * it -> val ;
    s.erase(it1 , it2) ;
    s.insert({l , r , val}) ;
    return abs(sum - sum2) ;
}
int n ;
struct Node {
    int v ;
    int nxt ;
};
const int N = 1e5 + 10 ;
Node e[N << 1] ;
int cnt = 0 ;
int head[N] ;
inline void Add(int u , int v) {
    e[++ cnt].v = v ;
    e[cnt].nxt = head[u] ;
    head[u] = cnt ;
    return ;
}
int top[N] ;
int id[N] ; int size[N] ;
int d[N] ; int idx = 0 ;
int fa[N] ; int son[N] ;
inline void Dfs1(int u) {
    size[u] = 1 ;
    for(register int i = head[u] ; i ; i = e[i].nxt ) {
        int v = e[i].v ;
        if(v == fa[u]) continue ;
        d[v] = d[u] + 1 ;
        fa[v] = u ;
        Dfs1(v) ;
        size[u] += size[v] ;
        if(size[v] > size[son[u]]) son[u] = v ;
    }
    return ;
}
inline void Dfs2(int u , int t) {
    id[u] = ++ idx ;
    top[u] = t ;
    if(! son[u]) return ;
    Dfs2(son[u] , t) ;
    for(register int i = head[u] ; i ; i = e[i].nxt) {
        int v = e[i].v ;
        if((v ^ fa[u]) && (v ^ son[u])) Dfs2(v , v) ;
    }
}
inline int getopt() { string s = "" ;
    register char c = getchar() ;
    while(isspace(c)) c = getchar() ;
    while(! isspace(c)) {
        s += c ;
        c = getchar() ;
    }
    if(s == "install") return 1 ;
    if(s == "uninstall") return 0 ;
}
inline int Change_Range(int x , int y) {
    int fx = top[x] ;
    int fy = top[y] ;
    int ans = 0 ;
    while(fx ^ fy) {
        if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
        ans += Assign(id[fx] , id[x] , 1) ;
        x = fa[fx] ;
        fx = top[x] ;
    }
    if(id[x] > id[y]) swap(x , y) ;
    ans += Assign(id[x] , id[y] , 1) ;
    return ans ;
}
inline int Uninstall(int x) {
    return Assign(id[x] , id[x] + size[x] - 1 , 0) ;
}
signed main() {
#ifdef Online_Judge
    freopen("testdata.in" , "r" , stdin) ;
    freopen("testdata2.out" , "w" , stdout) ;
#endif
    n = read() ;
    s.insert({1 , n + 1 , 0}) ;
    for(register int i = 2 ; i <= n ; i ++) {
        int u = read() ; u ++ ;
        Add(u , i) ;
        Add(i , u) ;
    }
    Dfs1(1) ;
    Dfs2(1 , 1) ;
    for(register int t = read() ; t -- ; ) {
        int opt = getopt() ;
        if(opt == 1) {
            int x = read() ; x ++ ;
            write(Change_Range(x , 1)) ;
        }
        if(opt == 0) {
            int x = read() ; x ++ ;
            write(Uninstall(x)) ;
        }
    }
    return 0 ;
}

[SDOI2011] staining

This problem is also ODT
But the difference is that this problem is a continuous number of colors color intervals counted once so tree line or difficult to maintain. (It should be.)

//Isaunoya
#include<bits/stdc++.h>
using namespace std ;
inline int read() {
    register int x = 0 ;
    register int f = 1 ;
    register char c = getchar() ;
    for( ; ! isdigit(c) ; c = getchar()) if(c == '-') f = -1 ;
    for( ; isdigit(c) ; c = getchar()) x = (x << 1) + (x << 3) + (c & 15) ;
    return x * f ;
}
int st[105] ;
template < typename T > inline void write(T x , char c = '\n') {
    int tp = 0 ;
    if(x == 0) return (void) puts("0") ;
    if(x < 0) putchar('-') , x = -x ;
    for( ; x ; x /= 10) st[++ tp] = x % 10 ;
    for( ; tp ; tp --) putchar(st[tp] + '0') ;
    putchar(c) ;
}
//#define Online_Judge

struct node {
    int l ;
    int r ;
    mutable int val ;
    bool operator < (const node & x) const {
        return l < x.l ;
    }
};
set < node > s ;

#define slt set < node > :: iterator
inline slt Split(int pos) {
    slt it (-- s.upper_bound({pos})) ;
    if(it -> l == pos) return it ;
    int l = it -> l ;
    int r = it -> r ;
    int val = it -> val ;
    s.erase(it) ;
    s.insert({l , pos - 1 , val}) ;
    return s.insert({pos , r , val}).first ;
}
inline void Assign(int l , int r , int val) {
    slt itr = Split(r + 1) ;
    slt itl = Split(l) ;
    s.erase(itl , itr) ;
    s.insert({l , r , val}) ;
    return ;
}
int n ;
struct Node {
    int v ;
    int nxt ;
};
const int N = 1e5 + 10 ;
int a[N] ;
Node e[N << 1] ;
int cnt = 0 ;
int head[N] ;
inline void Add(int u , int v) {
    e[++ cnt].v = v ;
    e[cnt].nxt = head[u] ;
    head[u] = cnt ;
    return ;
}
int top[N] ;
int id[N] ;
int size[N] ;
int d[N] ;
int idx = 0 ;
int fa[N] ;
int son[N] ;
int fst[N] ;
inline void Dfs1(int u) {
    size[u] = 1 ;
    for(register int i = head[u] ; i ; i = e[i].nxt ) {
        int v = e[i].v ;
        if(v == fa[u]) continue ;
        d[v] = d[u] + 1 ;
        fa[v] = u ;
        Dfs1(v) ;
        size[u] += size[v] ;
        if(size[v] > size[son[u]]) son[u] = v ;
    }
    return ;
}
inline void Dfs2(int u , int t) {
    id[u] = ++ idx ;
    top[u] = t ;
    a[idx] = fst[u] ;
    if(! son[u]) return ;
    Dfs2(son[u] , t) ;
    for(register int i = head[u] ; i ; i = e[i].nxt) {
        int v = e[i].v ;
        if((v ^ fa[u]) && (v ^ son[u])) Dfs2(v , v) ;
    }
}
inline int getopt() {
    register char c = getchar() ;
    while(isspace(c)) c = getchar() ;
    return c == 'Q' ;
}
inline void Change_Range(int x , int y , int val) {
    int fx = top[x] ;
    int fy = top[y] ;
    while(fx ^ fy) {
        if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
        Assign(id[fx] , id[x] , val) ;
        x = fa[fx] ;
        fx = top[x] ;
    }
    if(id[x] > id[y]) swap(x , y) ;
    Assign(id[x] , id[y] , val) ;
}
#define swap(x , y) x ^= y ^= x ^= y
inline int Query_Range(int x , int y) {
    int ans = 0 ;
    int lasta = 0 ;
    int lastb = 0 ;
    int fx = top[x] ;
    int fy = top[y] ;
    slt itl , itr ;
    while(fx ^ fy) {
        if(d[fx] > d[fy]) {
            itr = Split(id[x] + 1) , itl = Split(id[fx]) ;
            for(-- itr ; ; --itr) {
                if(itr -> val ^ lasta)
                    lasta = itr -> val , ++ ans ;
                if(itr == itl) break;
            }
            x = fa[fx] ;
            fx = top[x] ;
        } else {
//          swap(x , y) , swap(fx , fy) ;
            itr = Split(id[y] + 1) , itl = Split(id[fy]) ;
            for(-- itr ; ; --itr) {
                if(itr -> val ^ lastb)
                    lastb = itr -> val , ++ ans ;
                if(itr == itl) break;
            }
            y = fa[fy] ;
            fy = top[y] ;
        }
    }
    if(id[x] > id[y]) {
        itr = Split(id[x] + 1) , itl = Split(id[y]) ;
        for(-- itr ; ; --itr) {
            if(itr -> val ^ lasta)
                lasta = itr -> val , ++ ans ;
            if(itr == itl) break;
        }
    } else {
        itr = Split(id[y] + 1) , itl = Split(id[x]) ;
        for(-- itr ; ; --itr) {
            if(itr -> val ^ lastb)
                lastb = itr -> val , ++ ans ;
            if(itr == itl) break;
        }
    }
    return ans - (lasta == lastb) ;
}
signed main() {
#ifdef Online_Judge
    freopen("testdata.in" , "r" , stdin) ;
    freopen("testdata2.out" , "w" , stdout) ;
#endif
    n = read() ;
    int t = read() ;
    for(register int i = 1 ; i <= n ; i ++) fst[i] = read() ;
    for(register int i = 2 ; i <= n ; i ++) {
        int u = read() ;
        int v = read() ;
        Add(u , v) ;
        Add(v , u) ;
    }
    Dfs1(1) ;
    Dfs2(1 , 1) ;
    for(register int i = 1 ; i <= n ; i ++) s.insert({i , i , a[i]}) ;
    for( ; t -- ; ) {
        int opt = getopt() ;
        if(opt == 1) {
            int x = read() , y = read() ;
            write(Query_Range(x , y));
        }
        if(opt == 0) {
            int x = read() , y = read() , val = read() ;
            Change_Range(x , y , val) ;
        }
    }
    return 0 ;
}

[HAOI2015] operation tree

  • Action 1: the right point of a node x increases a.
  • Operation 2: The subtree rooted at some node x of weights of all points are point increases a.
  • Operation 3: interrogation points right path to a node x to the root node and all.

It is clear that the board is a problem ah.

// Isaunoya
#include <bits/stdc++.h>
using namespace std ;
inline int read() { register int res = 0 ; register int f = 1 ; register char c ;
#define gc c = getchar()
    while(isspace(gc)) ; if(c == '-') f = -1 , gc ;
    while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(gc)) ;
    return res * f ;
}
#define int long long
int n , m , r ;
const int N = 1000000 + 5 ;
struct E{ int v ;int nxt ; } ;
E edge[N << 1] ;
int a[N] ; int fa[N] ; int w[N] ; int id[N] ; int son[N] ;
int cnt = 0 ; int head[N] ; int Add[N << 2] , laz[N << 2] ;
int dep[N] , siz[N] , t[N] ;
inline void Add_Edge(register int u , register int v) { edge[++ cnt].v = v ; edge[cnt].nxt = head[u] ; head[u] = cnt ; return ; }
#define l(x) x << 1
#define r(x) x << 1 | 1
inline void Push_down(register int x , register int len) {
    laz[l(x)] += laz[x] ; laz[r(x)] += laz[x] ;
    Add[l(x)] += laz[x] * (len - (len >> 1)) ; Add[r(x)] += laz[x] * (len >> 1) ;
    laz[x] = 0 ; return ;
}
inline void Build(register int l , register int r , register int rt) {
    if(l == r) { Add[rt] = a[l] ;  return ; }
    register int mid = l + r >> 1 ;
    Build(l , mid , l(rt)) ; Build(mid + 1 , r , r(rt)) ;
    Add[rt] = (Add[l(rt)] + Add[r(rt)])  ;
}
inline void Update(register int a , register int b , register int l  , register int r , register int rt , register int k) {
    if(a <= l and r <= b) { laz[rt] += k ; Add[rt] += k * (r - l + 1) ; }
    else {
        if(laz[rt]) Push_down(rt , r - l + 1) ;
        register int mid = l + r >> 1 ;
        if(a <= mid) Update(a , b , l , mid , l(rt) , k) ;
        if(b > mid) Update(a , b , mid + 1 , r , r(rt) , k) ;
        Add[rt] = (Add[l(rt)] + Add[r(rt)])  ;
    }
}
int res = 0 ;
inline void query(register int a , register int b , register int  l , register int r , register int rt) {
    if(a <= l and r <= b) { res = (res + Add[rt])  ; return ; }
    else {
        if(laz[rt]) Push_down(rt , r - l + 1) ;
        register int mid = l + r >> 1 ;
        if(a <= mid) query(a , b , l , mid , l(rt)) ;
        if(b > mid) query(a , b , mid + 1 , r , r(rt)) ;
    }
}
inline int Query(register int a , register int b , register int l , register int r , register int rt) {
    res = 0 ; query(a , b , l , r , rt) ;
    return res  ;
}
inline void Upd_Range(register int x , register int y , register int k) {
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
         Update(id[t[x]] , id[x] , 1 , n , 1 , k) ;
         x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    Update(id[x] , id[y] , 1 , n , 1 , k) ;
}
inline int Query_Range(register int x , register int y) {
    int ans = 0 ;
    while(t[x] != t[y]) {
        if(dep[t[x]] < dep[t[y]]) swap(x , y) ;
        ans += Query(id[t[x]] , id[x] , 1 , n , 1) ;
        x = fa[t[x]] ;
    }
    if(dep[x] > dep[y]) swap(x , y) ;
    ans += Query(id[x] , id[y] , 1 , n , 1) ;
    return ans ;
}
inline int Qson(register int x) { return Query(id[x] , id[x] + siz[x] - 1 , 1 , n , 1) ; }
inline void Updson(register int x , register int k) { Update(id[x] , id[x] + siz[x] - 1 , 1 , n , 1 , k) ; return ; }
inline void Dfs1(register int x , register int f , register int deep) {
    dep[x] = deep ; fa[x] = f ; siz[x] = 1 ;
    int max_son = -1 ;
    for(register int i = head[x] ; i ; i = edge[i].nxt) {
        register int v = edge[i].v ;
        if(v == f) continue ;
        Dfs1(v , x , deep + 1) ;siz[x] += siz[v] ;
        if(siz[v] > max_son) max_son = siz[v] , son[x] = v ;
    }
}
int tot = 0 ;
inline void Dfs2(register int x , register int tf) {
    id[x] = ++ tot ; a[tot] = w[x] ; t[x] = tf ;
    if(! son[x]) return ;
    Dfs2(son[x] , tf) ;
    for(register int i = head[x] ; i ; i = edge[i].nxt) {
        int v = edge[i].v ;
        if(v == fa[x] or v == son[x]) continue ;
        Dfs2(v , v) ;
    }
}
signed main() {
    n = read() ; m = read() ; r = 1 ;
    for(register int i = 1 ; i <= n ; i ++) w[i] = read() ;
    for(register int i = 1 ; i <= n - 1 ; i ++) {
        int u = read() , v = read() ;
        Add_Edge(u , v) ;
        Add_Edge(v , u) ;
    }
    Dfs1(r , 0 , 1) ; Dfs2(r , r) ; Build(1 , n , 1) ;
    for( ; m -- ; ) {
        register int opt = read() ;
        if(opt == 1) {
            int x = read() , a = read() ;
            Upd_Range(x , x , a) ;
        }
        if(opt == 2) {
            int x = read() , z = read() ;
            Updson(x , z) ;
        }
        if(opt == 3) {
            int x = read() ;
            printf("%lld\n" , Query_Range(x , r)) ;
        }
    }
    return 0 ;
}

Guess you like

Origin www.cnblogs.com/Isaunoya/p/11619823.html