树链剖分模板+讲解
2016-05-06 17:13
260 查看
树链剖分的详解这里写得很好。我的标程与它的做法一样。
树链剖分的作用相当于在树上做线段树。
具体做法是通过一个点的dfs序来代替点的编号
设有重边和轻边
重边相连的子树是所有子树中大小最大的
那么它相连的点就叫做重儿子
为了保证一条重链上的dfs序连续,遍历时优先遍历重儿子
那么一条重链可以通过线段树直接处理
而一条路径最多经过log条链,可能是重链,可能是轻边组成的若干条长度为1的链
时间复杂度是log方的
找重链和重儿子通过两次递归实现
做法可以像下面标程一样,每次从x,y中找出其链顶深的进行处理
也可以把两边倒lca的分开做,打起来更方便一点,代码量差不多
模板题
【ZJOI2008】树的统计
在一颗树上,区间查询,单点修改。
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
标程
树链剖分的作用相当于在树上做线段树。
具体做法是通过一个点的dfs序来代替点的编号
设有重边和轻边
重边相连的子树是所有子树中大小最大的
那么它相连的点就叫做重儿子
为了保证一条重链上的dfs序连续,遍历时优先遍历重儿子
那么一条重链可以通过线段树直接处理
而一条路径最多经过log条链,可能是重链,可能是轻边组成的若干条长度为1的链
时间复杂度是log方的
找重链和重儿子通过两次递归实现
做法可以像下面标程一样,每次从x,y中找出其链顶深的进行处理
也可以把两边倒lca的分开做,打起来更方便一点,代码量差不多
模板题
【ZJOI2008】树的统计
在一颗树上,区间查询,单点修改。
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
标程
#include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib> #include <cstring> #include <iostream> #define fo(i,a,b) for(ll i=a;i<=b;i++) #define max(a,b) ((a)>(b)?(a):(b)) #define ll long long #define N 30100 int n,a ,last[N*10],next[N*10],to[N*10],tot,size ,deep ,dfn ,son ,fa ,top ,an; struct note { int mx,sum; }; note tree[N*10]; void putin(int x,int y) { next[++tot]=last[x];last[x]=tot;to[tot]=y; } void dg1(int x) { size[x]=1;int jy=0; for(int i=last[x];i;i=next[i]) { int k=to[i]; if (deep[k]!=0) continue; fa[k]=x;deep[k]=deep[x]+1;dg1(k);size[x]+=size[k]; if (size[k]>jy) son[x]=k,jy=size[k]; } } void dg2(int x,int y) { dfn[x]=++tot;if (son[x]) top[son[x]]=top[x],dg2(son[x],x); for(int i=last[x];i;i=next[i]) { int k=to[i]; if (k==son[x] || k==y) continue; top[k]=k;dg2(k,x); } } void change(int v,int i,int j,int x,int y) { if (i==j) { tree[v].mx=y;tree[v].sum=y;return;} int mid;mid=(i+j)/2; if (x<=mid) change(v*2,i,mid,x,y); else change(v*2+1,mid+1,j,x,y); tree[v].mx=max(tree[v*2].mx,tree[v*2+1].mx); tree[v].sum=tree[v*2].sum+tree[v*2+1].sum; } void get(int v,int i,int j,int x,int y,int jy) { if (i==x && j==y){ if (jy==1) an+=tree[v].sum;else an=max(an,tree[v].mx);return;} int mid;mid=(i+j)/2; if (y<=mid) get(v*2,i,mid,x,y,jy); else if(x>mid) get(v*2+1,mid+1,j,x,y,jy); else get(v*2,i,mid,x,mid,jy),get(v*2+1,mid+1,j,mid+1,y,jy); } int lct(int x,int y,int jy) { int ans,bz=1; ans=jy==1?0:-2147483647; while (x!=y) { int f1=top[x],f2=top[y];an=jy==1?0:-2147483647; if (f1!=f2) { if (deep[f1]>=deep[f2]) { get(1,1,tot,dfn[f1],dfn[x],jy); x=fa[f1]; } else { get(1,1,tot,dfn[f2],dfn[y],jy); y=fa[f2]; } } else { if (deep[x]<deep[y]) get(1,1,tot,dfn[x],dfn[y],jy); else get(1,1,tot,dfn[y],dfn[x],jy); if (jy==1) ans+=an;else ans=max(ans,an); bz=0; break; } if (jy==1) ans+=an;else ans=max(ans,an); } if (x!=0 && x==y && bz) { an=jy==1?0:-2147483647; get(1,1,tot,dfn[x],dfn[y],jy); if (jy==1) ans+=an;else ans=max(ans,an); } return ans; } int main() { scanf("%d",&n); fo(i,1,n-1) { int x,y; scanf("%d%d",&x,&y); putin(x,y);putin(y,x); } fo(i,1,n) scanf("%d",&a[i]); deep[1]=1;top[1]=1;dg1(1); tot=0;dg2(1,0); fo(i,1,n) change(1,1,tot,dfn[i],a[i]); int ac;scanf("%d\n",&ac); for(;ac;ac--) { char ch;scanf("%c",&ch);scanf("%c",&ch); int x,y; if (ch=='M') { scanf("AX %d %d\n",&x,&y); printf("%d\n",lct(x,y,2)); } if (ch=='S') { scanf("UM %d %d\n",&x,&y); printf("%d\n",lct(x,y,1)); } if (ch=='H') { scanf("ANGE %d %d\n",&x,&y); change(1,1,tot,dfn[x],y); } } }
相关文章推荐
- 使用Java快速入门Thrift
- 第一次使用Struts2的注解功能
- unknown type name''",did you mean""
- Fork & Pull Request
- 移动端触屏滑动,JS事件
- Http与https的总结
- Thrift下Java客户端与服务器端的开发
- JAVA逻辑运算符
- Mockito
- Andorid总结 - Bound Services
- springMVC中web.xml配置解析
- 二叉树非递归遍历
- layoutSubviews和drawRect:(CGRect)rect的用法探讨
- LOG4J配置详解及样例一个
- logic标签遍历map map中存放的是 List集合对象
- leetcode_169_Majority Element(C++)(easy)
- hive 基本操作
- 缩放Fresco图片
- c++
- 图片压缩