首页 > 其他分享 >[学习笔记] 树链剖分 - 图论 & 数据结构

[学习笔记] 树链剖分 - 图论 & 数据结构

时间:2024-06-19 21:58:49浏览次数:9  
标签:图论 剖分 int tu 树链 tv dfn ans id

树链剖分

怎么说呢,感觉只要不是求最大最小值好像都可以用树上查分代替。

例题

[ZJOI2008] 树的统计 - 单点修改 树链查询

树链剖分板子,不多说了,代码注意细节就行。该用dfn的地方不要把点的编号传进去。

#include<bits/stdc++.h>
using namespace std;
#define ls (id<<1)
#define rs (id<<1 | 1)
const int N = 3e5 + 5;
int n, h[N], cnt, val[N], q, son[N], size[N], dep[N], fa[N], dfn[N], top[N], rnk[N], tot;
struct edge{ int v, nxt; }e[N];
struct node{ int l, r, mx, sum; }t[N<<2];
inline void add(int u, int v){ e[++cnt] = (edge){v, h[u]}; h[u] = cnt; }
inline void dfs1(int u){
	size[u] = 1, son[u] = -1;
	for(int i=h[u]; i; i=e[i].nxt){
		int v = e[i].v;
		if(!dep[v]){
			dep[v] = dep[u] + 1;
			fa[v] = u;
			dfs1(v);
			size[u] += size[v];
			if(son[u] == -1 || size[v] > size[son[u]]) son[u] = v;
		}
	}
}
inline void dfs2(int u, int t){
	top[u] = t, rnk[dfn[u]=++tot] = u;
	if(son[u] == -1) return;
	dfs2(son[u], t);
	for(int i=h[u]; i; i=e[i].nxt){
		int v = e[i].v;
		if(v != son[u] && v != fa[u]) dfs2(v, v);
	}
}
inline void pushup(int id){
	t[id].sum = t[ls].sum + t[rs].sum;
	t[id].mx = max(t[ls].mx, t[rs].mx);
}
inline void build(int id, int l, int r){
	t[id].l = l, t[id].r = r;
	if(l == r){
		t[id].mx = t[id].sum = val[rnk[l]];
		return;
	}
	int mid = (l + r) >> 1;
	build(ls, l, mid), build(rs, mid+1, r);
	pushup(id);
}
inline void modify(int id, int v){
	if(t[id].l == v && t[id].r == v){
		t[id].sum = t[id].mx = val[rnk[v]];
		return;
	}
	int mid = (t[id].l + t[id].r) >> 1;
	modify(v<=mid?ls:rs, v);
	pushup(id);
}
inline int query_sum(int id, int l, int r){
	if(t[id].l >= l && r >= t[id].r) return t[id].sum;
	int mid = (t[id].l + t[id].r) >> 1, ans = 0;
	if(l <= mid) ans += query_sum(ls, l, r);
	if(r > mid) ans += query_sum(rs, l, r);
	return ans;
}
inline int query_max(int id, int l, int r){
	if(t[id].l >= l && r >= t[id].r) return t[id].mx;
	int mid = (t[id].l + t[id].r) >> 1, ans = INT_MIN;
	if(l <= mid) ans = max(ans, query_max(ls, l, r));
	if(r > mid) ans = max(ans, query_max(rs, l, r));
	return ans;
}
inline int qsum(int u, int v){
	int tu = top[u], tv = top[v], ans = 0;
	while(tu != tv){
		if(dep[tu] > dep[tv])
			ans += query_sum(1, dfn[tu], dfn[u]), u = fa[tu];
		else 
			ans += query_sum(1, dfn[tv], dfn[v]), v = fa[tv];
		tu = top[u], tv = top[v];
	}
	if(dfn[u] >= dfn[v]) ans += query_sum(1, dfn[v], dfn[u]);
	else ans += query_sum(1, dfn[u], dfn[v]);
	return ans;
}
inline int qmax(int u, int v){
	int tu = top[u], tv = top[v], ans = INT_MIN;
	while(tu != tv){
		if(dep[tu] >= dep[tv])
			ans = max(ans, query_max(1, dfn[tu], dfn[u])), u = fa[tu];
		else
			ans = max(ans, query_max(1, dfn[tv], dfn[v])), v = fa[tv];
		tu = top[u], tv = top[v];
	}
	if(dfn[u] >= dfn[v]) ans = max(ans, query_max(1, dfn[v], dfn[u]));
	else ans = max(ans, query_max(1, dfn[u], dfn[v]));
	return ans;
}
signed main(){
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n;
	for(int i=1, a, b; i<n; ++i) cin>>a>>b, add(a, b), add(b, a);
	for(int i=1; i<=n; ++i) cin>>val[i];
	dep[1] = 1, fa[1] = 1, dfs1(1); dfs2(1, 1);
	build(1, 1, n);
	cin>>q;
	for(int i=1; i<=q; ++i){
		string opt; int a, b;
		cin>>opt>>a>>b;
		if(opt == "CHANGE") val[a] = b, modify(1, dfn[a]); //It's very easy to make mistakes
		else if(opt == "QMAX") cout<<qmax(a, b)<<'\n';
		else cout<<qsum(a, b)<<'\n';
	} return 0;
}

标签:图论,剖分,int,tu,树链,tv,dfn,ans,id
From: https://www.cnblogs.com/xiaolemc/p/18257528

相关文章

  • 重链剖分与线段树
    树链剖分将整棵树可以铺到线性的去维护,于是利用线段树等可维护线性数组的数据结构,就可以做到很多事情了当然也包括省赛的J题--奇偶最小生成树,并且线段树还支持修改操作,这是ST表与普通倍增维护做不到的这是没有模数的代码:intn,m;llw[N];inthead[N],cnt;structE......
  • 树链剖分
    基本概念将树中的点重新编号,使得树中任意一条路径,都可以转化成O(logn)段连续区间1.将一棵树转化成一个序列2.将树中的任意一段路径转化成logn段连续区间(线段树,树状数组)重链剖分重儿子:子树数量最多的根节点(只有一个,多个都是,任选一个即可)轻儿子:其余儿子重边:重儿......
  • 大厂面试高频题目——图论
    797.所有可能的路径给你一个有n个节点的有向无环图(DAG),请你找出所有从节点0到节点n-1的路径并输出(不要求按特定顺序)graph[i]是一个从节点i可以访问的所有节点的列表(即从节点i到节点graph[i][j]存在一条有向边)。思考深搜dfs模板题。classSolution:def__in......
  • 【图论】欧拉图
    欧拉回路EulerianCycle:通过图中每条边恰好一次的回路欧拉通路EulerianPath:通过图中每条边恰好一次的通路欧拉图:具有欧拉回路的图半欧拉图:具有欧拉通路但不具有欧拉回路的图欧拉图中所有顶点的度数都是偶数。若G是欧拉图,则它为若干个环的并,且每条边被包含在奇数个环内。......
  • 【数据结构】图论入门
    引入数据的逻辑结构:集合:数据元素间除“同属于一个集合”外,无其他关系线性结构:一个对多个,例如:线性表、栈、队列树形结构:一个对多个,例如:树图形结构:多个对多个,例如:图图的基本概念及术语图:G=(V,E)V:顶点(数据元素)的有穷非空集合E:边的有穷集合图的类型定义无向图:每......
  • 图论-SPFA与差分约束
    闻道有先后,术业有专攻当用来判断负环的时候,SPFA还挺好用的intpre[N];voidprint_path(ints,intt){if(s==t){cout<<s;return;}print_path(s,pre[t]);cout<<""<<t;}inthead[N],cnt;structEdge{intfrom,to,nxt,c;}e[......
  • 图论
    1图论1.1图的建立1.1.1领接表边权建图importjava.util.ArrayList;importjava.util.List;importjava.util.Scanner;publicclassMain{//定义图的邻接表表示staticList<int[]>[]g;//节点数staticintn;//保存某种状态或结果的数组......
  • 最短路图论
    dijkstraCode:#include<bits/stdc++.h>usingnamespacestd;typedefpair<int,int>pii;constintN=1e5+5,inf=INT_MAX;intn,m,dis[N],s;//structnode{//intfrom,to,w,val;//};boolvis[N];vector<pii>edge......
  • 二叉树链式结构的前序、中序、后序、层序遍历
    文章目录一、二叉树创建二、前序遍历概念以及解释代码三、中序遍历概念及解释代码四、后序遍历概念及解释代码五、层序遍历概念及解释代码一、二叉树创建&mesp; 实现二叉树的遍历,我们要先手搓出一个二叉树,在次基础上实现二叉树的前序、中序、后序、层序遍历。......
  • 知识点整理 - 连通性相关 | 《综述图论中连通性及相关问题的一些处理方法》学习笔记
    是ix35老师论文的学习笔记,同时也用作连通性相关知识梳理。可能不会包含很多定义,只会挑重要的写。会包含一些例题。定义与记号\(u\rightsquigarrowv\)代表\(u\)到\(v\)的一条路径。有时也会用这个记号表示连通性。无向图点/边连通度:若\(u,v\)任意点割集大小不小......