zoukankan      html  css  js  c++  java
  • 树链剖分(从入门到入土。)

    前置知识:线段树,链式前向星,LCA,DFS序

    好了就当你都会了。不会也没关系。

    树链剖分通常的操作:
    1.x -> y 的路径上修改 2.x -> y 的路径上查询 3. 对于 x 的子树修改 4.对于 x 的子树查询。

    一般还有换根操作。树剖也也可以做LCA以及差分操作(但是树剖好像就直接修改了不需要差分)。

    树链剖分有两个DFS 这两个DFS就是把一棵树变成一个序列。 然后就可以用数据结构来维护了。

    第一个DFS 用来求 (fa)(祖先节点) (size)(子树大小)(son)(重儿子) (d)(深度)
    重儿子指的是(size)较大的儿子节点。
    第二个DFS 用来求(top)(这条链上最顶端的点) (id)(编号)以及其他的赋值操作。 但是重儿子要先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) ;
      }
    }
    

    这段代码求的就是下图的结果。

    对于这张图 (top) 指的是重链上最靠上的位置。即链的最高处。
    (Question:) 如果对于最右下的那个节点 top 是自己 那么不就死循环了吗 ?
    请读者仔细思考这个问题。

    假装你会线段树了。
    那么我们想 怎么做树上的修改呢?
    (id) 把这个树变成一个序列。
    没错 就是跳链对于每条重链 你可以一下到顶端 那么你直接修改这条重链上的值就可以了(数据结构维护)
    万一 一次重链跳不到那里怎么办?
    那么说明了这个点并不是重儿子 我们想办法让它跳上去。
    反复循环。 DFS1中记录了父亲节点 你将它变成它重链上的最高处的父亲节点。
    因为这条重链修改过了 所以不用管重复。一直反复跳 它会跳到 链的 LCA 处 这也是为什么可以求LCA的原因
    对于上面留下的问题…也是一个关于复杂度的证明
    假设最坏情况 你的修改/查询的点 没有一条边在重链上 你每次都要 往上 fa 一次
    但是这种情况 出现在 满多叉树上 这样的话 就是最坏的复杂度 即 (logn)
    那么一般还要套一个线段树 所以 最坏的复杂度是 (n log^2 n)

    写在最后:如果没有规定根的话 建议根 随机呢 万一弄个满二叉树卡你 你随机一下就可以避免被卡。
    rand()%n+1
    善意提醒:建议您下面的代码不要复制粘贴呢 自己一遍遍手打。。

    【模板】树链剖分

    #include <bits/stdc++.h>
    using namespace std ;
    using ll = long long ;
    using pii = pair < int , int > ;
    using vii = vector < int > ;
    constexpr int N = 1e5 + 10 ;
    int n , m , r , p , val[N] , a[N] ;
    vii G[N] ; int sum[N << 2] , tag[N << 2] ;
    void pushup(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1] ; sum[rt] %= p ; }
    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) ;
      pushup(rt) ;
    }
    void pushdown(int rt , int l , int r) {
      if(! tag[rt]) return ;
      int mid = l + r >> 1 ;
      tag[rt << 1] += tag[rt] ; tag[rt << 1 | 1] += tag[rt] ;
      sum[rt << 1] += tag[rt] * (mid - l + 1) ; sum[rt << 1 | 1] += tag[rt] * (r - mid) ;
      tag[rt] = 0 ;
    }
    void change(int a , int b , int l , int r , int rt , int val) {
      if(a <= l && r <= b) { tag[rt] += val ; sum[rt] += (r - l + 1) * val ; return ; }
      pushdown(rt , l , r) ;
      int mid = l + r >> 1 ;
      if(a <= mid) change(a , b , l , mid , rt << 1 , val) ;
      if(b > mid) change(a , b , mid + 1 , r , rt << 1 | 1 , val) ;
      pushup(rt) ;
    }
    int query(int a , int b , int l ,int r , int rt) {
      if(a <= l && r <= b) { return sum[rt] ; }
      pushdown(rt , l , r) ;
      int mid = l + r >> 1 , res = 0 ;
      if(a <= mid) res += query(a , b , l , mid , rt << 1) ;
      if(b > mid) res += query(a , b , mid + 1 , r , rt << 1 | 1) ;
      return res % p ;
    }
    int fa[N] , sz[N] , son[N] , d[N] , top[N] , id[N] , idx = 0 ;
    signed main() {
      ios :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ;
      cin >> n >> m >> r >> p;
      for(int i = 1 ; i <= n ; i ++) { cin >> val[i] ; }
      for(int i = 2 ; i <= n ; i ++) { int u , v ; cin >> u >> v ; G[u].push_back(v) ; G[v].push_back(u) ; }
      function <void(int)> dfs = [&](int u) {
        sz[u] = 1 ; for(int v : G[u]) {
          if(v ^ fa[u]) { fa[v] = u ; d[v] = d[u] + 1 ; dfs(v) ; sz[u] += sz[v] ;if(sz[v] > sz[son[u]]) son[u] = v ; }
        }
      } ;
      function <void(int,int)> dfs2 = [&](int u , int t) {
        top[u] = t ; a[id[u] = ++ idx] = val[u] ;
        if(son[u]) dfs2(son[u] , t) ;
        for(int v : G[u]) if(v ^ fa[u] && v ^ son[u]) dfs2(v , v) ;
      } ;
      dfs(r) ; dfs2(r , r) ; build(1 , n , 1) ;
      auto change_range = [&](int x , int y , int val) {
        while(top[x] ^ top[y]) { if(d[top[x]] < d[top[y]]) swap(x , y) ; change(id[top[x]] , id[x] , 1 , n , 1 , val) ; x = fa[top[x]] ; }
        (d[x] < d[y]) ? change(id[x] , id[y] , 1 , n , 1 , val) : change(id[y] , id[x] , 1 , n , 1 , val) ;
      } ;
      auto query_range = [&](int x , int y) {
        int res = 0 ;
        while(top[x] ^ top[y]) { if(d[top[x]] < d[top[y]]) swap(x , y) ; res += query(id[top[x]] , id[x] , 1 , n , 1) ; x = fa[top[x]] ; }
        res += (d[x] < d[y]) ? query(id[x] , id[y] , 1 , n , 1) : query(id[y] , id[x] , 1 , n , 1) ;
        return res % p ;
      } ;
      while(m --) {
        int opt ; cin >> opt ;
        if(opt == 1) {
          int x , y , z ; cin >> x >> y >> z ;
          change_range(x , y , z) ;
        }
        if(opt == 2) {
          int x , y ; cin >> x >> y ;
          cout << query_range(x , y) << '
    ' ;
        }
        if(opt == 3) {
          int x , z ; cin >> x >> z ;
          change(id[x] , id[x] + sz[x] - 1 , 1 , n , 1 , z) ;
        }
        if(opt == 4) {
          int x ; cin >> x ;
          cout << query(id[x] , id[x] + sz[x] - 1 , 1 , n , 1) << '
    ' ;
        }
      }
      return 0 ;
    }
    
    

    (原来写的太丑了额

    [USACO11DEC]牧草种植Grass Planting

    链上修改 单点查询。
    对于这个题目 要修改的是边的权值。
    这里有一个技巧 是 把边的权值下传给点 然后把最上面的点忽略掉。(易证 这样是可以的。)
    然后进行基本的操作就可以了。

    #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
    " , Query_Range(u , v)) ;
      }
    	return 0 ;
    }
    

    Qtree1

    同样的边权化成点权 然后单点修改

    //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 = '
    ') { 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
    int n ;
    
    //============================================SegTree
    struct SegTree {
    	int val ;
    	int max ;
    };
    const int N = 2e5 + 10 ;
    SegTree t[N << 2] ;
    int a[N] ;
    inline void build(int l , int r , int rt) {
    	if( l == r ) {
    		t[rt].max = t[rt].val = a[l] ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	build(l , mid , rt << 1) ;
    	build(mid + 1 , r , rt << 1 | 1) ;
    	t[rt].max = max(t[rt << 1].max , t[rt << 1 | 1].max) ;
    }
    inline void Change(int x , int l , int r , int rt , int val) {
    	if(l == r) {
    		t[rt].max = t[rt].val = val ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	if(x <= mid) Change(x , l , mid , rt << 1 , val) ;
    	else Change(x , mid + 1 , r , rt << 1 | 1 ,val ) ;
    	t[rt].max = max(t[rt << 1].max , t[rt << 1 | 1].max) ;
    }
    inline int Query_Max(int a , int b , int  l, int r , int rt) {
    	if(a > b) return 0 ;
    	if(a <= l && r <= b) return t[rt].max ;
    	int ans = 0 ;
    	int mid = l + r >> 1 ;
    	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 ;
    }
    //========================================================================
    
    struct node {
    	int v ;
    	int nxt ;
    	int w ;
    };
    node e[N << 1] ;
    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 ;
    }
    int size[N] ;
    int son[N] ;
    int d[N] ;
    int fst[N] ;
    int id[N] ;
    int top[N] ;
    int fa[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 ;
    		fst[v] = e[i].w ;
    		fa[v] = u ;
    		Dfs1(v) ;
    		size[u] += size[v] ;
    		if(size[v] > size[son[u]]) son[u] = v ;
    	}
    }
    int idx = 0 ;
    inline void Dfs2(int u , int t) {
    	id[u] = ++ idx ;
    	a[idx] = fst[u] ;
    	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 Query_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 = max(ans , Query_Max(id[fx] , id[x] , 1 , n , 1)) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	if(id[x] > id[y]) swap(x , y) ;
    	ans = max(ans , Query_Max(id[x] + 1 , id[y] , 1 , n , 1)) ;
    	return ans ;
    }
    inline int getopt() {
    	string s ;
    	register char c = getchar() ;
    	while(isspace(c)) c = getchar() ;
    	while(! isspace(c)) {
    		s += c ;
    		c = getchar() ;
    	}
    	if(s == "DONE") return -1 ;
    	if(s == "QUERY") return 0 ;
    	return 1 ;
    }
    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 ; i ++) {
    		int u = read() , v = read() , w = read() ;
    		Add_Edge(u , v , w) ;
    		Add_Edge(v , u , w) ;
    	}
    	Dfs1(1) ;
    	Dfs2(1 , 1) ;
    	build(1 , n , 1) ;
    	while(1) {
    		int opt = getopt() ;
    		if(opt == -1) {
    			return 0 ;
    		}
    		if(opt == 0) {
    			int x = read() , y = read() ;
    			if(x == y) {
    				puts("0") ;
    				continue ;
    			}
    			else {
    				write(Query_Range(x , y)) ;
    			}
    		}
    		else {
    			int x = read() , y = read() ;
    			int u = e[x * 2 - 1].v ;
    			int v = e[x * 2].v ;
    			if(u == fa[v]) swap(u , v) ;
    			Change(id[u] , 1 , n , 1 , y) ;
    		}
    	}
    	return 0 ;
    } // 这份代码会T掉一个点…
    

    [USACO15DEC]最大流Max Flow

    树剖是可以求LCA的 以这题为例。
    这题是需要把压力给两个点 两个点加上1 然后这两个点的(LCA)减掉1 因为这个点也需要加上1 所以我们只能把这个1在(fa_LCA)减掉
    这样递归到最底下 然后一直往上加 显然就是这棵树的权值

    #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]树

    技巧题
    这题是可以在链上二分的 但是主流做法好像不是这个?
    链上二分要注意是反过来的。。

    #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
    " , f[Find(x)]) ;
    	}
    	return 0 ;
    }
    

    [国家集训队]旅游
    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 = '
    ') {
    	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]树的统计

    与模板题差不多。。

    //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 = '
    ') { 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 ;
    }
    

    [SHOI2012]魔法树

    //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 = '
    ') { 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
    //==============================================================edge
    struct node {
    	int v ;
    	int nxt ;
    };
    int n ;
    const int N = 100000 + 5 ;
    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 size[N] ;
    int son[N] ; int id[N] ;
    int idx = 0 ; int d[N] ;
    int top[N] ; int fa[N] ;
    //================================================================slpf
    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 ;
    		fa[v] = u ;
    		d[v] = d[u] + 1 ;
    		Dfs1(v) ;
    		size[u] += size[v] ;
    		if(size[v] > size[son[u]]) son[u] = v ;
    	}
    }
    
    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) ;
    	}
    }
    //=======================================================Segment_Tree
    struct Seg {
    	int sum ;
    	int tag ;
    };
    Seg t[N << 2] ;
    inline void Push_down(int rt , int l , int r) {
    	if(t[rt].tag) {
    		t[rt << 1].tag += t[rt].tag ;
    		t[rt << 1 | 1].tag += t[rt].tag ;
    		int mid = l + r >> 1 ;
    		t[rt << 1].sum += (mid - l + 1) * t[rt].tag ;
    		t[rt << 1 | 1].sum += (r - mid) * t[rt].tag ;
    		t[rt].tag = 0 ;
    		return ;
    	}
    }
    inline void Push_up(int rt) {
    	t[rt].sum = t[rt << 1].sum + t[rt << 1 | 1].sum ;
    }
    inline void build(int l , int r , int rt) {
    	if(l == r) {
    		t[rt].sum = 0 ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	build(l , mid , rt << 1) ;
    	build(mid + 1 , r , rt << 1 | 1) ;
    	Push_up(rt) ;
    }
    inline void Change(int a , int b , int l , int r , int rt , int val) {
    	if(a <= l && r <= b) {
    		t[rt].sum += (r - l + 1) * val ;
    		t[rt].tag += val ;
    		return ;
    	}
    	Push_down(rt , l , r) ;
    	int mid = l + r >> 1 ;
    	if(a <= mid) Change(a , b , l , mid , rt << 1 , val) ;
    	if(b > mid) Change(a , b , mid + 1 , r , rt << 1 | 1 , val) ;	
    	Push_up(rt) ;
    	return ;
    }
    inline int Query(int a , int b , int l , int r , int rt) {
    	if(a <= l && r <= b) return t[rt].sum ;
    	Push_down(rt , l , r) ;
    	int mid = l + r >> 1 ;
    	int 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 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) ;
    		Change(id[fx] , id[x] , 1 ,n , 1 , val) ;
    		x = fa[fx] ; 
    		fx = top[x] ;
    	}
    	if(id[x] > id[y]) swap(x , y) ;
    	Change(id[x] , id[y] , 1 , n , 1 , val) ;
    	return ;
    }
    //inline int Query_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 += Query(id[fx] , id[x] , 1 , n , 1) ;
    //		x = fa[fx] ;
    //		fx = top[x] ;
    //	}
    //	if(id[x] > id[y]) swap(x , y) ;
    //	ans += Query(id[x] , id[y] , 1 , n , 1) ;
    //	return ans ;
    //}
    inline int Query_Son(int x) { return Query(id[x] , id[x] + size[x] - 1 , 1 , n , 1) ; }
    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() ;
    		u ++ ; v ++ ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	Dfs1(1) ;
    	Dfs2(1 , 1) ;
    	build(1 , n , 1) ;
    	for(register int q = read() ; q -- ; ) {
    		register char c = getchar() ;
    		for( ; c != 'Q' && c != 'A' ; c = getchar()) ;
    		if(c == 'A') {
    			int x = read() , y = read() ;
    			x ++ , y ++ ;
    			int val = read() ;
    			Change_Range(x , y , val) ;
    		} 
    		if(c == 'Q') {
    			int x = read() ;
    			x ++ ;
    			write(Query_Son(x)) ;
    		} 
    	}
    	return 0 ;
    }
    

    APIO[部落冲突]
    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 = '
    ') { 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
    int n ;
    vector < pair < int , int > > v ;
    const int N = 3e5 + 10 ;
    int a[N] ;
    struct node {
    	int v ;
    	int nxt ;
    };
    node e[N << 1] ; int head[N] ;
    int cnt = 0 ;
    inline void Add(int u , int v) {
    	e[++ cnt].v = v ;
    	e[cnt].nxt = head[u] ;
    	head[u] = cnt ;
    	return ;
    } 
    int size[N] ;
    int top[N] , son[N] ;
    int fa[N] ; int id[N] ; int d[N] ;
    int idx = 0 ;
    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]) {
    			fa[v] = u ;
    			d[v] = d[u] + 1 ;
    			Dfs1(v) ;
    			size[u] += size[v] ;
    			if(size[son[u]] < size[v]) son[u] = v ;
    		}
    	}
    }
    inline void Dfs2(int u , int t) {
    	id[u] = ++ idx ;
    	top[u] = t ;
    	a[idx] = 0 ;
    	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] ;
    int tag[N << 2] ;
    inline void build(int l , int r , int rt) {
    	if(l == r) {
    		sum[rt] = a[l] ; 
    		tag[rt] = 0 ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	build(l , mid , rt << 1) ;
    	build(mid + 1 , r , rt << 1 | 1) ;
    	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1] ;
    	return ;
    }
    inline void Push_down(int rt , int l , int r) {
    	if(tag[rt]) {
    		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 Change(int a , int b , int l , int r , int rt , int val) {
    	if(a <= l && r <= b) {
    		sum[rt] += val * (r - l + 1) ;
    		tag[rt] += val ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	Push_down(rt , l , r) ;
    	if(a <= mid) Change(a , b , l , mid , rt << 1 , val) ;
    	if(b > mid) Change(a , b , mid + 1 , r , rt << 1 | 1 , val) ;
    	sum[rt] = sum[rt << 1] + sum[rt << 1 | 1] ;
    	return ;
    }
    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 ;
    	int ans = 0 ;
    	Push_down(rt , l , r) ;
    	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 Query_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 += Query(id[fx] , id[x] , 1 , n , 1) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	if(id[x] > id[y]) swap(x , y) ;
    	ans += Query(id[x] + 1 , id[y] , 1 , n , 1) ;
    	return ans ;
    }
    inline void Change_Range(int x , int y , int val) {
    	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) ;
    		Change(id[fx] , id[x] , 1 , n , 1 , val) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	if(id[x] > id[y]) swap(x , y) ;
    	Change(id[x] + 1 , id[y] , 1 , n , 1 , val) ;
    }
    signed main() {
    #ifdef Online_Judge
    	freopen("testdata.in" , "r" , stdin) ;
    	freopen("testdata2.out" , "w" , stdout) ;
    #endif
    	n = read() ; int q = read() ;
    	for(register int  i = 1 ; i <= n - 1 ; i ++) {
    		int u = read() ;
    		int v = read() ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	Dfs1(1) ;
    	Dfs2(1 , 1) ;
    	build(1 , n , 1) ;
    	for(register int i = 1 ; i <= q ; i ++) {
    		register char c = getchar() ;
    		for( ; c != 'C' && c != 'Q' && c != 'U' ; c = getchar()) ;
    		if(c == 'Q') {
    			int x = read() , y = read() ;
    			if(Query_Range(x , y)) puts("No") ;
    			else puts("Yes") ;
    		}
    		if(c == 'C') {
    			int x = read() , y = read() ;
    			Change_Range(x , y , 1) ;
    			v.push_back(make_pair(x , y)) ;
    		}
    		if(c == 'U') {
    			int num = read() - 1 ;
    			int x = v[num].first ;
    			int y = v[num].second ;
    			Change_Range(x , y , - 1) ;
    		}
    	}
    	return 0 ;
    }
    

    [HAOI2015]树上操作

    • 操作 1 :把某个节点 x 的点权增加 a 。
    • 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    • 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    很显然是个板子题啊。

    // 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
    " , Query_Range(x , r)) ;
    		}
        }
        return 0 ;
    }
    

    上面都是用线段树维护的序列 其实树剖不一定要用 线段树 只要是数据结构都可以
    比如说ODT 什么的 如果不会ODT也没什么关系 你会用线段树当然更好 ODT 是可以卡掉的 但是在树上问题 通常不容易卡掉。

    CF343D Water Tree

    //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 = '
    ') { 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
    
    int n ;
    struct ODT {
    	int l , r ;
    	mutable int val ;
    	bool operator <(const ODT & x) const{
    		return l < x.l ;
    	}
    };
    set < ODT > s ;
    typedef set < ODT > :: iterator IT ;
    inline IT Split(int pos) {
    	IT it(-- s.upper_bound({pos , 0 , 0})) ;
    	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) {
    	IT itr(Split(r + 1)) ;
    	IT itl(Split(l)) ;
    	s.erase(itl , itr) ;
    	s.insert({l , r , val}) ;
    	return ;
    }
    //===========================================ODT
    struct node {
    	int v ;
    	int nxt ;
    } ;
    const int N = 500000 + 5 ;
    node e[N << 1] ;
    int head[N] ;
    int cnt = 0 ;
    inline void Add(int u ,int v) {
    	e[++ cnt].v = v ;
    	e[cnt].nxt = head[u] ;
    	head[u] = cnt ;
    	return ;
    }
    int size[N] ; int d[N] ;
    int top[N] ; int idx = 0 ;
    int id[N] ; 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 ;
    	} 
    }
    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 void Change_Range(int x) {
    	int fx = top[x] ;
    	while(fx ^ 1) {
    		Assign(id[fx] , id[x] , 0) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	Assign(id[1] , id[x] , 0) ;
    }
    inline void Query(int x) {
    	IT pos(Split(x)) ;
    	write(pos -> val) ;
    }
    signed main() {
    #ifndef 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() ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	Dfs1(1) ;
    	Dfs2(1 , 1) ;
    	s.insert({0 , n + 1 , 0}) ;
    	for(register int m = read() ; m -- ; ) {
    		int opt = read() ;
    		if(opt == 1) {
    			int v = read() ;
    			Assign(id[v] , id[v] + size[v] - 1 , 1) ;
    		}
    		if(opt == 2) {
    			int v = read() ;
    			Change_Range(v) ;
    		}
    		if(opt == 3) {
    			int v = read() ;
    			Query(id[v]) ;
    		}
    	}
    	return 0 ;
    }
    

    [NOI2015]软件包管理器
    因为 软件之间是有依赖关系的

    • 每次安装软件 就把根节点到x软件路径上的值全部变为1
    • 同理 每次卸载软件 就把x以及它的子树的值变为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 = '
    ') { 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]染色

    这题也是个ODT
    不过不同的是 这题是区间的颜色数量 连续的颜色算一次 这样的话 线段树还是很难维护的。(应该也可以。)

    //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 = '
    ') {
    	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 ;
    }
    

    [SDOI2014]旅行
    动态开点。

    • “CC x c“:城市x的居民全体改信了c教;
    • “CW x w“:城市x的评级调整为w;
    • “QS x y“:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
    • “QM x y“:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级最大值。
      基本操作还是一样。
      如果没有 第一个 操作 是可以树剖+线段树做的 但是有了第一个操作 就只能用动态开点做了。
    //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 = '
    ') { 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
    int n ;
    const int N = 5e5 + 5 ;
    
    int val[N] ;
    int cl[N] ;
    struct node {
    	int v ;
    	int nxt ;
    };
    node e[N << 1] ;
    int L[N << 2] , R[N << 2] ;
    int head[N] ; int cnt = 0 ;
    inline void Add(int u ,int v) {
    	e[++ cnt].v = v ;
    	e[cnt].nxt = head[u] ; 
    	head[u] = cnt ;
    	return ;
    }
    int a[N] ;
    int fa[N] ;
    int top[N] ;
    int id[N] ;
    int size[N] ;
    int son[N] ;
    int d[N] ; int RT[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 ;
    		fa[v] = u ;
    		d[v] = d[u] + 1 ;
    		Dfs1(v) ;
    		size[u] += size[v] ;
    		if(size[v] > size[son[u]]) son[u] = v ;
    	}
    }
    int idx = 0 ;
    inline void Dfs2(int u , int t) {
    	top[u] = t ;
    	id[u] = ++ idx ;
    	a[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 mx[N << 2] ;
    int sum[N << 2];
    
    inline void Push_Up(int rt) {
    	mx[rt] = max(mx[L[rt]] , mx[R[rt]]) ;
    	sum[rt] = sum[L[rt]] + sum[R[rt]] ;
    	return ;
    }
    int c = 0 ;
    
    inline void Modify(int & p , int l , int r , int k , int val) {//开点。
    	if(! p) p = ++ c ;
    	if(l >= r) {
    		mx[p] = sum[p] = val ;
    		return ;
    	} 
    	int mid = l + r >> 1 ;
    	if(k <= mid) Modify(L[p] , l , mid , k , val) ;
    	else Modify(R[p] , mid + 1 , r , k , val) ;
    	Push_Up(p) ;
    	if(! sum[p]) p = 0 ;
    }
    inline int Query_Max(int p , int a , int b , int l , int r) { // 查询
    	if(! p) return -1 ;
    	if(a <= l && r <= b) return mx[p] ;
    	int mid = l + r >> 1 ;
    	int ans = - 1 ;
    	if(a <= mid) ans = max(ans , Query_Max(L[p] , a , b,  l , mid)) ;
    	if(b > mid) ans = max(ans , Query_Max(R[p] , a , b, mid + 1 , r)) ;
    	return ans ;
    }
    inline int Query_Sum(int p , int a , int b , int  l , int r){//查询
    	if(! p) return 0 ;
    	if(a <= l && r <= b) return sum[p] ;
    	int mid = l + r >> 1 ;
    	int ans = 0 ;
    	if(a <= mid) ans += Query_Sum(L[p] , a , b , l , mid) ;
    	if(b > mid) ans += Query_Sum(R[p] , a , b , mid + 1 , r) ;
    	return ans ;
    }
    inline int Max_Range(int x , int y) {
    	int fx = top[x] ;
    	int fy = top[y] ;
    	int ans = 0 ;
    	int t = cl[x] ;
    	while(fx ^ fy) {
    		if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
    		ans = max(ans , Query_Max(RT[t] , id[fx] , id[x] , 1 , idx)) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	if(id[x] > id[y]) swap(x , y) ;
    	ans = max(ans , Query_Max(RT[t] , id[x] , id[y] , 1 , idx)) ;
    	return ans ;
    }
    inline int Query_Range(int x , int y) {
    	int fx = top[x] ;
    	int fy = top[y] ;
    	int ans = 0 ;
    	int t = cl[x] ;
    	while(fx ^ fy) {
    		if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
    		ans += Query_Sum(RT[t] , id[fx] , id[x] , 1 , idx) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	if(id[x] > id[y]) swap(x , y) ;
    //	cout << ans << endl ;
    	ans += Query_Sum(RT[t] , id[x] , id[y] , 1 , idx) ;
    //	cout << ans << endl ;
    	return ans ;
    }
    signed main() {
    #ifdef Online_Judge
    	freopen("testdata.in" , "r" , stdin) ;
    	freopen("testdata2.out" , "w" , stdout) ;
    #endif
    	n = read() ; int q = read() ;
    	for(register int i = 1 ; i <= n ;i ++) {
    		val[i] = read() ;
    		cl[i] = read() ;
    	}
    	for(register int i = 1 ; i <= n - 1 ; i ++) {
    		int u = read() , v = read() ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	Dfs1(1) ;
    	Dfs2(1 , 1) ;
    //	puts("1") ;
    	for(register int i = 1 ; i <= n ; i ++) Modify(RT[cl[a[i]]] , 1 , idx ,  i , val[a[i]]) ;
    	for(register int i = 1 ; i <= q ; i ++) {
    		register char c = getchar() ;
    		for( ; c != 'C' && c != 'Q' ; c = getchar()) ;
    		register char c2 = getchar() ;
    		if(c == 'C' && c2 == 'C') {
    			int c = read() , x = read() ;
    			Modify(RT[cl[c]] , 1 , idx , id[c] , 0) ;//删点
    			cl[c] = x ;
    			Modify(RT[cl[c]] , 1 , idx , id[c] , val[c]) ;//开点
    		}
    		if(c == 'C' && c2 == 'W') {
    			int c = read() , x = read() ;
    			val[c] = x ;
    			Modify(RT[cl[c]] , 1 , idx , id[c] , val[c]) ; // 修改
    		}
    		if(c == 'Q' && c2 == 'S') {
    			int x = read() , y = read() ;
    			write(Query_Range(x , y)) ;
    		}
    		if(c == 'Q' && c2 == 'M') {
    			int x = read() , y  =read() ;
    			write(Max_Range(x , y)) ;
    		}
    	}
    	return 0 ;
    }
    

    Count on a tree

    给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
    强制在线,那么考虑静态主席树求区间第k小。。 还是一样的套路。。 如果不会主席树 建议 -> HERE

    //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 = '
    ') { 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
    const int N = 1e5 + 10 ;
    const int M = N << 5 ;
    int n , q ; int m ;
    int sum[M] , L[M] , R[M] ;
    int a[N] , b[N] , rt[N] ;
    struct node{
    	int v ;
    	int nxt ;
    };
    node e[N << 1] ;
    int head[N] ;
    int fa[N] , size[N] , d[N] , son[N] , top[N] ;
    int cnt =  0 ; 
    inline void Add(int u , int v) {
    	e[ ++ cnt] . v = v ;
    	e[ cnt] . nxt = head[u] ;
    	head[u] = cnt ;
    	return ;
    }
    int tot = 0 ;
    inline void Update(int last , int & now , int l , int r , int x) { // 动态开点 主席树基操
    	sum[now = ++ tot] = sum[last] + 1 ;
    	if(l == r) return ;
    	int mid = l + r >> 1 ;
    	if(x <= mid) R[now] = R[last] , Update(L[last] , L[now] , l , mid , x) ;
    	else L[now] = L[last] , Update(R[last] , R[now] , mid + 1 , r , x) ;
    	return ;
    }
    inline int Query(int a , int b , int lca ,int lca_fa , int l , int r , int k) { // 求 k 小…
    	if(l >= r) return l ;
    	int x = sum[L[a]] + sum[L[b]] - sum[L[lca]] - sum[L[lca_fa]] ;
    	int mid = l + r >> 1 ;
    	if(x >= k) return Query(L[a] , L[b] , L[lca] , L[lca_fa] , l , mid , k) ;
    	else return Query(R[a] , R[b] , R[lca] , R[lca_fa] , mid + 1 , r , k - x) ;
    }
    
    inline void Dfs(int u) {
    	size[u] = 1 ;
    	Update(rt[fa[u]] , rt[u] , 1 , m , a[u]) ;
    	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) {
    	int fx = top[x] ;
    	int 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 ;
    }
    signed main() {
    #ifdef Online_Judge
    	freopen("testdata.in" , "r" , stdin) ;
    	freopen("testdata2.out" , "w" , stdout) ;
    #endif
    	n = read() , q = read() ;
    	for(register int i = 1 ; i <= n ; i ++) a[i] = read() ;
    	for(register int i = 1 ; i <= n ; i ++) b[i] = a[i] ;
    	sort(b + 1 , b + n + 1) ;
    	m = unique(b + 1 , b + 1 + n) - b - 1 ;
    	for(register int i = 1 ; i <= n ; i ++) 
    		a[i] = lower_bound(b + 1 , b + m + 1 , a[i]) - b ;
    	for(register int i = 1 ; i <= n - 1 ; i ++) {
    		int u = read() , v = read() ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	Dfs(1) ;
    	Dfs2(1 , 1) ;
    	int ans = 0 ;
    	for(register int i = 1 ; i <= q ; i ++) {
    		int x = read() ^ ans , y = read() ;
    		int lca = Lca(x , y) ;
    		int z = read() ;
    		write(ans = b[Query(rt[x] , rt[y] , rt[lca] , rt[fa[lca]] , 1 , m , z)]) ;
    	}
    	return 0 ;
    }
    

    [Vani有约会]雨天的尾巴

    对于这题是一个线段树合并的问题
    线段树合并例题 -> sol
    递归求解 合并线段树的信息。

    //Isaunoya
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #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 = '
    ') {
    	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
    int n , m ;
    const int N = 1e5 + 10 ;
    int lc[N << 6] ;
    int rc[N << 6] ;
    int rt[N << 6] ;
    int mx[N << 6] , id[N << 6] ;
    int cnt = 0 ;
    inline void Push_up(int rt) {
    	if(mx[lc[rt]] >= mx[rc[rt]]) {
    		mx[rt] = mx[lc[rt]] ;
    		id[rt] = id[lc[rt]] ;
    	} else {
    		mx[rt] = mx[rc[rt]] ;
    		id[rt] = id[rc[rt]] ;
    	}
    }
    inline int Merge(int a , int b , int  l , int r) {
    	if(! a || ! b) return a | b ;
    	if(l == r) {
    		mx[a] += mx[b] , id[a] = l ;
    		return a ;
    	}
    	int mid = l + r >> 1 ;
    	lc[a] = Merge(lc[a] , lc[b] , l , mid) ;
    	rc[a] = Merge(rc[a] , rc[b] , mid + 1 , r) ;
    	return Push_up(a) , a ;
    }
    inline void Insert(int & p , int l , int r , int pos , int v) {
    	if(! p) p = ++ cnt ;
    	if(l == r) {
    		id[p] = l ;
    		mx[p] += v ;
    		return ;
    	}
    	int mid = l + r >> 1 ;
    	if(pos <= mid) Insert(lc[p] , l , mid , pos , v) ;
    	else Insert(rc[p] , mid + 1 , r , pos , v) ;
    	Push_up(p) ;
    	return ;
    }
    struct node {
    	int v ;
    	int nxt ;
    };
    int tot = 0 ;
    int head[N] ;
    node e[N << 1] ;
    inline void Add(int u , int v) {
    	e[++ tot].v = v ;
    	e[tot].nxt = head[u] ;
    	head[u] = tot ;
    	return ;
    }
    int top[N] , fa[N] ;
    int d[N] , idx[N] ;
    int size[N] , son[N] ;
    int Idx = 0 ;
    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 ;
    		fa[v] = u ;
    		d[v] = d[u] + 1 ;
    		Dfs1(v) ;
    		size[u] += size[v] ;
    		if(size[v] > size[son[u]]) son[u] = v ;
    	}
    }
    inline void Dfs2(int u , int t) {
    	idx[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 GetLca(int x , int y) {
    	int fx = top[x] ;
    	int fy = top[y] ;
    	while(fx ^ fy) {
    		if(d[fx] < d[fy]) swap(fx , fy) , swap(x , y) ;
    		x = fa[fx] ;
    		fx = top[x] ;
    	}
    	if(d[x] > d[y]) swap(x , y) ;
    	return x ;
    }
    int ans[N] ;
    inline void GetAns(int u , int fa) {
    	for(register int i = head[u ] ; i ; i  = e[i].nxt) {
    		int v = e[i].v ;
    		if(v == fa) continue ;
    		GetAns(v , u) ;
    		rt[u] = Merge(rt[u] , rt[v] , 1 , N) ;
    	}
    	ans[u] = id[rt[u]] ;
    	if(mx[rt[u]] == 0) ans[u] = 0 ;
    }
    signed main() {
    #ifdef Online_Judge
    	freopen("testdata.in" , "r" , stdin) ;
    	freopen("testdata2.out" , "w" , stdout) ;
    #endif
    	n = read() ;
    	m = read() ;
    	for(register int i = 1 ; i <= n - 1 ; i ++) {
    		int u , v ;
    		u = read() , v = read() ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	Dfs1(1) ;
    	Dfs2(1 , 1) ;
    	for(register int i = 1 ; i <= m ; i ++) {
    		int x = read() , y = read() , z = read() ;
    		int lca = GetLca(x , y) ;
    		Insert(rt[lca] , 1 , N , z , - 1) ;
    		Insert(rt[fa[lca]] , 1 , N , z , - 1) ;
    		Insert(rt[x] , 1 , N , z , 1) ;
    		Insert(rt[y] , 1 , N , z , 1) ;
    	}
    	GetAns(1 , 0) ;
    	for(register int i = 1 ; i <= n ; i ++) write(ans[i]) ;
    	return 0 ;
    }
    
    • 这里还有一个重要操作:换根
    • 换根是一个比较重要的操作 "换根"不一定要重新DFS以及建树 只需要根据根所在的位置 和 查询的位置 分类讨论就可以了。
    • 但是你需要求一个 k - 1 级祖先(也就是最上面的那个的儿子节点) 所以需要一种倍增的想法

    [BZOJ3083][遥远的国度]

    //Isaunoya
    #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 ;
    }
    struct node {
    	int v , nxt ;
    } ;
    int n , m ;
    const int N = 100000 + 5 ;
    int a[N] ;
    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][22], size[N] , son[N] , d[N] ;
    inline void Dfs(int u) {
    	size[u] = 1 ;
    	for(register int i = 1 ; i <= 20 ; i ++) { // 倍增预处理
    		fa[u][i] = fa[fa[u][i - 1]][i - 1] ;
    		if(! fa[u][i]) break ;
    	}
    	for(register int i = head[u] ; i ; i = e[i].nxt){
    		int v = e[i].v ;
    		if(v == fa[u][0]) continue ;
    		fa[v][0] = u ;
    		d[v] = d[u] + 1 ;
    		Dfs(v) ;
    		size[u] += size[v] ;
    		if(size[son[u]] < size[v]) son[u] = v ;
    	}
    }
    int id[N] , idx = 0 ;
    int fst[N] , top[N] ;
    inline void Dfs2(int u , int t) {
    	id[u] = ++ idx ;
    	fst[idx] = a[u] ;
    	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][0]) && (v ^ son[u])) Dfs2(v , v) ;
    	}
    	return ;
    }
    int mn[N << 2] ;
    int tag[N << 2] ;
    inline void build(int l , int r , int rt) {
    	tag[rt] = 0 ;
    	if(l == r) { mn[rt] = fst[l] ; return ; }
    	int mid = l + r >> 1 ;
    	build(l , mid , rt << 1) ;
    	build(mid + 1 , r , rt << 1 | 1) ;
    	mn[rt] = min(mn[rt << 1] , mn[rt << 1 | 1]) ;
    }
    inline void Push_down(int rt) {
    	if(! tag[rt]) return ;
    	mn[rt << 1] = mn[rt << 1 | 1] = tag[rt << 1] = tag[rt << 1 | 1] = tag[rt] ;
    	return (void)(tag[rt]=0) ;
    }
    inline void Change(int a , int b , int  l, int r , int rt , int val) {
    	if(a <= l && r <= b) {
    		mn[rt] = tag[rt] = val ;
    		return ;
    	} Push_down(rt) ;
    	int mid = l + r >> 1 ;
    	if(a <= mid) Change(a , b , l , mid , rt << 1 , val) ;
    	if(b > mid) Change(a , b , mid + 1 , r , rt << 1 | 1 , val) ;
    	mn[rt] = min(mn[rt << 1] , mn[rt << 1 | 1]) ;
    }
    inline int Query(int a , int b , int  l, int r , int rt) {
    	if(a <= l && r <= b) return mn[rt] ;
    	Push_down(rt) ;
    	int mid = l + r >> 1 ;
    	int ans = INT_MAX ;
    	if(a <= mid) cmin(ans , Query(a , b , l , mid , rt << 1 )) ;
    	if(b > mid) cmin(ans , Query(a , b , mid + 1 , r , rt << 1 | 1)) ;
    	return ans ;
    }
    inline void Change_Range(int x , int y , int val) {
    	int fx = top[x] , fy = top[y] ;
    	while(fx ^ fy) {
    		if(d[fx] < d[fy]) swap(x , y) , swap(fx , fy) ;
    		Change(id[fx] , id[x] , 1 , n , 1 , val) ;
    		x = fa[fx][0] ;
    		fx = top[x] ;
    	}
    	if(d[x] > d[y]) swap(x , y) ;
    	Change(id[x] , id[y] , 1 , n , 1 , val) ;
    }
    inline int getfa(int x , int k) { // k 级祖先
    	for(register int i = 20 ; i >= 0 ; i --)
    		if(k >= (1 << i)) k ^= (1 << i) , x = fa[x][i] ;
    	return x ;
    }
    int root = 1 ;
    inline void getans(int x) { // 分类讨论
    	if(x == root) {//与根相同就是全局最大值即mn[1]
    		printf("%lld
    " , mn[1]) ;
    		return ;
    	}
    	int y = 0 ;
    	int p , q ;
    	if(d[x] < d[root] && fa[y = getfa(root , d[root] - d[x] - 1)][0] == x) {
    		p = Query(1 , id[y] - 1 , 1 , n , 1) ;
    		if(id[y] + size[y] <= n) q = Query(id[y] + size[y] , n , 1 , n , 1) ;
    		else q = INT_MAX ;
    		printf("%lld
    " , min(p , q)) ;
    	}
    	else printf("%lld
    " , Query(id[x] , id[x] + size[x] - 1 , 1 , n , 1)) ; // 子树中
    }
    signed main() {
    	n = read() ; m = read() ;
    	for(register int i = 1 ; i < n ; i ++) {
    		int u = read() , v = read() ;
    		Add(u , v) ;
    		Add(v , u) ;
    	}
    	for(register int i = 1 ; i <= n ; i ++) a[i] = read() ;
    	Dfs(1) ;
    	Dfs2(1 , 0) ;
    	root = read() ;
    	build(1 , n , 1) ;
    	for(register int i = 1 ; i <= m ; i ++) {
    		int opt = read() ;
    		if(opt == 1) {
    			root = read() ;
    		}
    		if(opt == 2) {
    			int x = read() , y = read() , val = read() ;
    			Change_Range(x , y , val) ;
    		}
    		if(opt == 3) {
    			int x = read() ;
    			getans(x) ;
    		}
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    小程序教程3
    小程序教程2
    小程序教程1
    sublime介绍常用插件和快捷键
    ionic1跨域问题
    上传文件到windows server, 导出文件到linux, 打包压缩
    windows远程管理服务winrm
    windows配置ssh服务
    前端:websocket脚本
    前端实现: 抓拍和定时弹出任务
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/11619823.html
Copyright © 2011-2022 走看看