【数据结构】树链剖分总结
来源:互联网 发布:马东的软件 编辑:程序博客网 时间:2024/06/06 00:14
树链剖分是一种基于树的算法,将树转化为线性结构(如线段树),可以说是一种应用性十分强的算法,并且在近年来的考题中也常常出现。但其实思维上并不是一个很困难的东西,实现起来也非常好写。
剖分技巧通常有三种:
1,随机剖分
2,盲目剖分
3,启发式剖分
在随机数据的情况下,三者的实际速度并没有太大差别,但如果数据有一定特征,那么前两个方法就会逊色不少。所以启发式剖分就是我们最常用的树链剖分方式。
启发式剖分:按照大小,将每个点连向最大子树的边成为重边,其他边称为轻边。由重边连接形成的链就称为重链。
启发式剖分有一个很重要的性质:
从根节点到任意一个节点的路径上最多经过
证明很容易想,这里就简单提及一下:
因为轻边所连接的子树大小不大于总子树大小的一半,所以每走一次轻边,能到达的点就会减少至少一半,因此最多只会经过
logn 条轻边。因为最多只走logn 条轻边,所以经过的重链数量也必然小于logn 。
实现:
对于树链剖分来说,实现技巧是比较关键的内容。
如果自己写,很容易写成200多行的大模板,然而有良好的实现技巧用不到100行就可以解决。
剖分:
树的剖分用两次dfs完成,
第一次:寻找重边,统计子树大小,父亲节点,构造深度信息。
void dfs1(int x,int fax,int deep){ dep[x]=deep; fa[x]=fax; son[x]=-1; sz[x]=1; for(int i=0;i<a[x].size();i++){ if(a[x][i]==fax) continue; dfs1(a[x][i],x,deep+1); sz[x]+=sz[a[x][i]]; if(son[x]==-1||sz[son[x]]<sz[a[x][i]]) son[x]=a[x][i]; }}
第二次:构造重链,按照DFS序将一条重链上的点置于数据结构上的相邻位置,标记重链顶端节点,构造DFS序的信息。
void dfs2(int x,int tp){ top[x]=tp; tid[x]=++dcnt; rnk[dcnt]=x; if(son[x]==-1) return; dfs2(son[x],tp); for(int i=0;i<a[x].size();i++) if(a[x][i]!=son[x]&&a[x][i]!=fa[x]) dfs2(a[x][i],a[x][i]);}
访问:
通常的访问会给出一个点对
处理方式和LCA有些许类似,详情可参照代码:
int Query(int x,int y){//求x,y两点路径上的边权和 int res=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); res+=Query1(1,n,1,tid[top[x]],tid[x]); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); res+=Query1(1,n,1,tid[x],tid[y]); return res;}
例题:Qtree
代码:
#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#define SF scanf#define PF printf#define MAXN 50010using namespace std;vector<int> a[MAXN],id[MAXN];int tree[MAXN*4],dcnt,n,t;int sz[MAXN],dep[MAXN],top[MAXN],son[MAXN],rnk[MAXN],tid[MAXN],fa[MAXN];int e2v[MAXN],v2e[MAXN],len[MAXN];void build(int l,int r,int id){ if(l==r){ tree[id]=len[v2e[rnk[l]]]; return ; } int mid=(l+r)>>1; build(l,mid,id*2); build(mid+1,r,id*2+1); tree[id]=max(tree[id*2],tree[id*2+1]);}void Change(int l,int r,int id,int del,int val){ if(l==r){ tree[id]=val; return ; } int mid=(l+r)>>1; if(del<=mid) Change(l,mid,id*2,del,val); else Change(mid+1,r,id*2+1,del,val); tree[id]=max(tree[id*2],tree[id*2+1]);}int Query(int l,int r,int id,int l1,int r1){ if(l1<=l&&r<=r1){ return tree[id]; } int mid=(l+r)>>1; if(mid>=r1) return Query(l,mid,id*2,l1,r1); if(mid<l1) return Query(mid+1,r,id*2+1,l1,r1); return max(Query(l,mid,id*2,l1,r1),Query(mid+1,r,id*2+1,l1,r1));}void dfs1(int x,int fax,int deep){ fa[x]=fax; dep[x]=deep; sz[x]=1; son[x]=-1; for(int i=0;i<a[x].size();i++){ int v=a[x][i]; if(v==fax) continue; e2v[id[x][i]]=v; v2e[v]=id[x][i]; dfs1(v,x,deep+1); sz[x]+=sz[v]; if(son[x]==-1||sz[v]>sz[son[x]]) son[x]=v; }}void dfs2(int x,int tp){ top[x]=tp; tid[x]=++dcnt; rnk[dcnt]=x; if(son[x]==-1) return ; dfs2(son[x],tp); for(int i=0;i<a[x].size();i++) if(a[x][i]!=son[x]&&a[x][i]!=fa[x]) dfs2(a[x][i],a[x][i]);}int Que(int x,int y){ int res=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]]) swap(x,y); res=max(res,Query(1,n,1,tid[top[x]],tid[x])); x=fa[top[x]]; } if(dep[x]>dep[y]) swap(x,y); if(x!=y) res=max(res,Query(1,n,1,tid[x]+1,tid[y])); return res;}void init(){ dcnt=0; memset(tree,0,sizeof tree); memset(a,0,sizeof a); memset(id,0,sizeof id);}char s[10];int main(){ //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); SF("%d",&t); int u,v,val; while(t--){ SF("%d",&n); init(); for(int i=1;i<n;i++){ SF("%d%d%d",&u,&v,&val); a[u].push_back(v); a[v].push_back(u); id[u].push_back(i); id[v].push_back(i); len[i]=val; } dfs1(1,0,1); dfs2(1,1); build(1,n,1); SF("%s",s); while(s[0]!='D'){ SF("%d%d",&u,&v); if(s[0]=='C'){ Change(1,n,1,tid[e2v[u]],v); } else{ PF("%d\n",Que(u,v)); } SF("%s",s); } }}
阅读全文
0 0
- 【数据结构】树链剖分总结
- 【数据结构】数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构总结
- 数据结构 总结
- 数据结构 总结
- 总结-数据结构
- 数据结构总结
- HDOJ1799 循环多少次?
- Linux CentOS配置yum源(阿里yum)
- ffmpeg常用编码参数含x264
- RabbitMQ应用实例Python版-监控
- 快捷键备忘录
- 【数据结构】树链剖分总结
- opencv库练习--参考SLAM十四讲5.3
- BZOJ3732: Network
- Twitch如何实现转码比FFmpeg性能提升65%?(下)
- Ubuntu 执行apt-get update时 Problem executing scripts APT::Update: 错误
- C语言的发展历史
- caffe中的Accuracy
- 计算机单位
- 关于VS项目平台的x86,x64,Any CPU以及Debug和Release