您的位置:首页 > 其它

树链剖分模板+讲解

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的路径上的节点的权值和

标程

#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);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: