zoukankan      html  css  js  c++  java
  • 树链剖分【模板】

    参考博客

    • 重儿子:对于每一个非叶子节点,它的儿子中 以那个儿子为根的子树节点数最大的儿子 为该节点的重儿子
    • 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子
    • 叶子节点没有重儿子也没有轻儿子(因为它没有儿子。。)
    • 重边:一个父亲连接他的重儿子的边称为重边 //原写法:连接任意两个重儿子的边叫做重边
    • 轻边:剩下的即为轻边
    • 重链:相邻重边连起来的 连接一条重儿子 的链叫重链
      • 对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链
      • 每一条重链以轻儿子为起点

    妙wa

    博客上讲的挺详细的,也比较简单易懂

    【树链剖分】

    感觉挺妙的,其实树剖并不是很难,就是代码有些繁琐。

    /*
     * @Author: zhl
     * @Date: 2020-10-13 20:36:59
     */
    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i = a;i <= b;i++)
    #define repE(i,u) for(int i = head[u];i;i = E[i].next)
    #define mid (l+r>>1)
    #define lo (o<<1)
    #define ro (o<<1|1)
    
    using namespace std;
    const int N = 4e5 + 10;
    int A[N];
    int n, m, root, mod;
    
    struct Edge {
    	int to, next;
    }E[N << 1];
    
    int head[N], tot;
    void addEdge(int from, int to) {
    	E[++tot] = Edge{ to,head[from] };
    	head[from] = tot++;
    }
    
    int fa[N], sz[N], Tfa[N], dep[N], son[N];
    
    //dfs1处理dep,sz,fa,son(重儿子)
    void dfs1(int u, int p) {
    	fa[u] = p;
    	dep[u] = dep[p] + 1;
    	sz[u] = 1;
    	int mx = -1;
    	repE(i, u) {
    		int v = E[i].to;
    		if (v == p)continue;
    		dfs1(v, u);
    		sz[u] += sz[v];
    		if (sz[v] > mx)mx = sz[v], son[u] = v;
    	}
    }
    
    int cnt;
    int id[N], val[N], top[N];
    //dfs2 剖分数链
    void dfs2(int u, int topf) {
    	id[u] = ++cnt;
    	val[cnt] = A[u];
    	top[u] = topf;
    	if (!son[u])return;
    	dfs2(son[u], topf);
    	repE(i, u) {
    		int v = E[i].to;
    		if (v == fa[u] or v == son[u])continue;
    		dfs2(v, v);
    	}
    }
    
    int sum[N << 2], lz[N << 2];
    int x, y, z;
    void push_down(int o, int l, int r) {
    	if (!lz[o])return;
    	lz[lo] += lz[o];
    	lz[ro] += lz[o];
    	sum[lo] = (sum[lo] + lz[o] * (mid - l + 1)) % mod;
    	sum[ro] = (sum[ro] + lz[o] * (r - mid)) % mod;
    	lz[o] = 0;
    }
    
    void build(int o, int l, int r) {
    	if (l == r) {
    		sum[o] = val[l];
    		return;
    	}
    	build(lo, l, mid);
    	build(ro, mid + 1, r);
    	sum[o] += sum[lo] + sum[ro];
    }
    
    void updt(int o, int l, int r) {
    	if (x <= l and r <= y) {
    		lz[o] = (lz[o] + z) % mod;
    		sum[o] = (sum[o] + z * (r - l + 1)) % mod;
    		return;
    	}
    	push_down(o, l, r);
    	if (x <= mid)updt(lo, l, mid);
    	if (y > mid)updt(ro, mid + 1, r);
    	sum[o] = (sum[lo] + sum[ro]) % mod;
    }
    
    int query(int o, int l, int r) {
    	if (x <= l and r <= y) {
    		return sum[o];
    	}
    	int ans = 0;
    	push_down(o, l, r);
    	if (x <= mid)ans = (ans + query(lo, l, mid)) % mod;
    	if (y > mid)ans = (ans + query(ro, mid + 1, r)) % mod;
    	return ans;
    }
    
    int query_path(int a, int b) {
    	int ans = 0;
    	while (top[a] != top[b]) {
    		if (dep[top[a]] < dep[top[b]])swap(a, b);
    		x = id[top[a]]; y = id[a];
    		ans = (ans + query(1, 1, cnt)) % mod;
    		a = fa[top[a]];
    	}
    	if (dep[a] > dep[b])swap(a, b);
    	x = id[a]; y = id[b];
    	ans = (ans + query(1, 1, cnt)) % mod;
    	return ans;
    }
    void updt_path(int a, int b, int k) {
    	k %= mod;
    	while (top[a] != top[b]) {
    		if (dep[top[a]] < dep[top[b]])swap(a, b);
    		x = id[top[a]]; y = id[a]; z = k;
    		updt(1, 1, cnt);
    		a = fa[top[a]];
    	}
    	if (dep[a] > dep[b])swap(a, b);
    	x = id[a]; y = id[b]; z = k;
    	updt(1, 1, cnt);
    }
    
    int main() {
    	scanf("%d%d%d%d", &n, &m, &root, &mod);
    	for (int i = 1; i <= n; i++)scanf("%d", A + i);
    
    	for (int i = 1; i < n; i++) {
    		scanf("%d%d", &x, &y);
    		addEdge(x, y); addEdge(y, x);
    	}
    	dfs1(root, 0);
    	dfs2(root, root);
    	build(1, 1, cnt);
    	while (m--) {
    		int op; scanf("%d", &op);
    		int a, b, c;
    		if (op == 1) {//a,b 路径 + c
    			scanf("%d%d%d", &a, &b, &c);
    			updt_path(a, b, c);
    		}
    		if (op == 2) {//a,b 路径sum
    			scanf("%d%d", &a, &b);
    			printf("%d
    ", query_path(a, b));
    		}
    		if (op == 3) {//a的subtree + c
    			scanf("%d%d", &a, &c);
    			x = id[a]; y = id[a] + sz[a] - 1;
    			z = c;
    			updt(1, 1, cnt);
    		}
    		if (op == 4) {
    			scanf("%d", &a);
    			x = id[a]; y = id[a] + sz[a] - 1;
    			printf("%d
    ", query(1, 1, cnt));
    		}
    	}
    }
    
    /*
    5 50 2 24000
    7 3 7 8 0
    1 2
    1 5
    3 1
    4 1
    */
    

    debug 一晚上的罪魁祸首。

    代码一刻钟,

    debug两小时

    bug 一字符

  • 相关阅读:
    Numpy
    啊大大阿达
    asda
    啊大大
    初识python
    初识python
    初识python
    初识python
    初识python
    初识python
  • 原文地址:https://www.cnblogs.com/sduwh/p/13811727.html
Copyright © 2011-2022 走看看