• [图论神器]树链剖分


    用途

    解决树上问题,一般来说如果有查询又有询问就非常的复杂。如果用LCA你更改了树就会原地爆炸,因而树链剖分的用途就显现出来了。虽然板子多,还不如打暴力

    预备概念

    重儿子:父亲结点的所有儿子结点中,子树拥有结点数最多的结点。轻儿子:父亲结点除了重儿子以外的所有儿子。重边:父亲结点与重儿子的连边。轻边:父亲结点与轻儿子的连边。重链:所有重边所组成的一条链。

    变量声明

    fa[u]:保存点u的父亲结点d[u]:保存点u的深度size[u]:保存以u为根节点的子树的结点个数son[u]:保存点u的重儿子top[u]:保存点u所在重链的顶端结点id[u]:保存点u进行重新编号后的新的编号

    操作

    首先进行一次dfs求出除id,top外的数组。

    void dfs1(int step,int fa1){
    	size[step] = 1;
    	for (int i = 0;i < G[step].size();i ++){
    		int u = G[step][i];
    		if (u != fa1){
    			fa[u] = step;
    			dep[u] = dep[step] + 1;
    			dfs1(u,step);
    			size[step] += size[u];
    			if (size[u] > size[son[step]])
    				son[step] = u;
    		}
    	}
    }
    

    然后,在进行一次dfs求出id,top

    void dfs2(int step,int fa1){
    	id[step] = ++ cnt;
    	w1[cnt] = w[step];
    	top[step] = fa1;
    	if (!son[step])
    		return ;
    	dfs2(son[step],fa1);
    	for (int i = 0;i < G[step].size();i ++){
    		int u = G[step][i];
    		if (u != fa[step] && u != son[step])
    			dfs2(u,u);
    	}
    }
    

    然后我就不知道该怎么写了…
    由于很久以前的东西(2019年起稿,快一年了),不想写了,所以直接贴代码,保存一下模板吧

    void solve1(int u,int v,int x){//区间修改
    	while (top[u] != top[v]){
    		if (dep[top[u]] < dep[top[v]])
    			swap(u,v);
    		update(1,x,id[top[u]],id[u]);
    		u = fa[top[u]];
    	}
    	if (dep[u] > dep[v])
    		swap(u,v);
    	update(1,x,id[u],id[v]);
    }
    int solve2(int u,int v){//区间查询
    	int ans = 0;
    	while (top[u] != top[v]){
    		if (dep[top[u]] < dep[top[v]])
    			swap(u,v);
    		ans = (ans + find(1,id[top[u]],id[u])) % p;
    		u = fa[top[u]];
    	}
    	if (dep[u] > dep[v])
    		swap(u,v);
    	ans = (ans + find(1,id[u],id[v])) % p;
    	return ans;
    }
    

    线段树维护

    void build (int i,int l,int r){
    	tree[i].l = l,tree[i].r = r;
    	if(l == r){
    		tree[i].x = w1[l];
    		return ;
    	}
    	int mid = (l + r) / 2;
    	build (i * 2,l,mid);
    	build (i * 2 + 1,mid + 1,r);
    	tree[i].x = (tree[i * 2].x + tree[i * 2 + 1].x) % p;
    }
    void pushdown(int x){
    	tree[x * 2].x = (tree[x * 2].x + (tree[x * 2].r - tree[x * 2].l + 1) * lazy[x] % p) % p;
    	tree[x * 2 + 1].x = (tree[x * 2 + 1].x + (tree[x * 2 + 1].r - tree[x * 2 + 1].l + 1) * lazy[x] % p) % p;
    	lazy[x * 2] = (lazy[x * 2] + lazy[x]) % p; 
    	lazy[x * 2 + 1] = (lazy[x * 2 + 1] + lazy[x]) % p;
    	lazy[x] = 0;
    }
    void update(int i,int x,int l,int r){
    	if (tree[i].l > r || tree[i].r < l)
    		return ;
    	if (tree[i].l >= l && tree[i].r <= r){
    		lazy[i] = (lazy[i] + x) % p;
    		tree[i].x = (tree[i].x + (tree[i].r - tree[i].l + 1) * x) % p;
    		return ;
    	}
    	if (lazy[i])
    		pushdown(i);
    	update(i * 2,x,l,r);
    	update(i * 2 + 1,x,l,r);
    	tree[i].x = (tree[i * 2].x + tree[i * 2 + 1].x) % p;
    }
    int find(int i,int l,int r){
    	if (tree[i].l > r || tree[i].r < l)
    		return 0;
    	if (tree[i].l >= l && tree[i].r <= r)
    		return tree[i].x;
    	else {
    		if (lazy[i])
    			pushdown(i);
    		int sum = 0;
    		sum = (sum + find(i * 2,l,r)) % p;
    		sum = (sum + find(i * 2 + 1,l,r)) % p;
    		return sum;
    	}
    }
    
  • 相关阅读:
    783. Minimum Distance Between BST Nodes
    290. Word Pattern
    155. Min Stack
    HDU 6069 Counting Divisors (素数+筛法)
    BZOJ 2038 小Z的袜子(hose) (莫队算法)
    HDU 6127 Hard challenge (极角扫描)
    HDU 6096 String (AC自动机)
    LightOJ 1268 Unlucky Strings (KMP+矩阵快速幂)
    CodeForces 219D Choosing Capital for Treeland (树形DP)
    ZOJ 3201 Tree of Tree (树形DP)
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13566652.html
Copyright © 2020-2023  润新知