树链剖分 模板小记
\[树链剖分~模板小记
\]
\(Q.\) 树链剖分的背景?
\(A.\) 连通且无环的树
\(Q.\) 树链剖分的作用?
\(A.\) 大幅增加码量 (
\(A.\) 将一棵树变成几条链 树形变成线形 减少处理难度
\(Q.\) 树链剖分能处理哪些问题?
\(A_1.\) 修改的有:
- 将\(x\)节点\(+~or\times val\)
- 将\(x\)到\(y\)这条路径上所有节点\(+~or\times val\)
- 将以\(x\)为根的子树内所有节点\(+~or\times val\)
\(A_2.\) 查询的有:
- 查询\(x\)到\(y\)这条路径的权值和\(/\)乘积
- 查询\(x\)到\(y\)这条路径的最大值\(/\)最小值
- 查询以\(x\)为根的子树内的权值和\(/\)乘积
- 查询以\(x\)为根的子树内的最大值\(/\)最小值
这些操作通过线段树维护
\(Q.\) 树链剖分的概念?
\(A.\)
- 重儿子 指对于每个非叶子节点 它的儿子中 儿子数量最多的那个儿子
- 轻儿子 指对于每个非叶子节点 其余的儿子 \((\)非重儿子\()\)
- 重边 连接任意两个重儿子的边
- 轻边 非重边 其余的边即轻边
- 重链 相邻重边连起来的 连接一条重儿子的链
- 对于叶子节点 若其为轻儿子 则有一条以自己为起点的长度为\(1\)的链
- 每一条重链以轻儿子为起点
用两个\(dfs\) 完成下列事情
\(dfs1:\)
- 记录每个点的深度\(dep[]\)
- 记录每个点的父亲\(fa[]\)
- 记录每个非叶子节点的子树大小\(size[]\)
- 记录每个非叶子节点的重儿子编号\(son[]\)
\(CODE:\)
点击查看代码
void dfs(int x,int father,int deep)
{
dep[x]=deep; //深度
fa[x]=father; //父亲
size[x]=1; //子树大小
int numson=-1; //重儿子个数(可以不用)
for(int i=head[x];i;i=edge[i].next)
{
int qwq=edge[i].to;
if(qwq==father) continue;
dfs(qwq,x,deep+1);
size[x]+=size[qwq];
if(size[qwq]>numson)
son[x]=qwq,numson=size[qwq];
}
}
\(dfs2:\)
- 记录每个点的\(dfs\)序
- 每个点的编号赋到dfs序编号上 \((\)也可以直接赋初值\()\)
- 处理每条链的顶端 以及链
\(CODE:\)
点击查看代码
void dfs2(int x,int topN)
{
dfn[x]=++num; //dfs序
id[num]=x; //编号
top[x]=topN; //链的顶端
if(!son[x]) return;
dfs2(son[x],topN);
for(int i=head[x];i;i=edge[i].next)
{
int qwq=edge[i].to;
if(qwq==fa[x]||qwq==son[x]) continue;
dfs2(qwq,qwq); //见上面概念7
}
}
区间查询 \(/\) 修改:
区间和查询例子
点击查看代码
int queryS(int x,int y)
{
int res=0;
while(top[x]!=top[y]) //不在一条链上
{
if(dep[top[x]]<dep[top[y]]) //x改为深度更深
swap(x,y);
res+=SumQ(1,1,n,dfn[top[x]],dfn[x]); //加上x点到x所在链顶端的点权和
x=fa[top[x]]; //x跳到链顶端上面一个点
}
if(dep[x]>dep[y]) swap(x,y); //同一条链了 深度改回去
res+=SumQ(1,1,n,dfn[x],dfn[y]); //再加上两个点的区间和
return res;
}
修改也同样 把求和操作改为修改操作即可
线段树嘛 大家都会就不用贴了\(qwq\)
例题 \(LuoguP3384~\)轻重链剖分\(/\)树链剖分
\(CODE:\)
小压了些行 仍有\(180\)行
点击查看代码
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n,m,root,Mod,res;
int tot,head[N],w[N],f[N];
struct node{int to,next;}edge[N];
struct SegmentTree{int val,lazy;}a[N<<2];
int son[N],id[N],fa[N],dfn,dep[N],size[N],top[N];
void add(int x,int y){
edge[++tot]=(node){y,head[x]};
head[x]=tot;
}
void up(int x){a[x].val=(a[x<<1].val+a[x<<1|1].val)%Mod;}
void down(int x,int len)
{
a[x<<1].lazy+=a[x].lazy;
a[x<<1|1].lazy+=a[x].lazy;
a[x<<1].val+=a[x].lazy*(len-(len>>1));
a[x<<1|1].val+=a[x].lazy*(len>>1);
a[x<<1].val%=Mod;
a[x<<1|1].val%=Mod;
a[x].lazy=0;
}
void build(int x,int l,int r)
{
if(l==r)
{
a[x].val=w[f[l]];
if(a[x].val>Mod) a[x].val%=Mod;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
up(x);
}
void query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)
{
(res+=a[x].val)%=Mod;
return;
}
else{
int mid=(l+r)>>1;
if(a[x].lazy) down(x,r-l+1);
if(L<=mid) query(x<<1,l,mid,L,R);
if(mid<R) query(x<<1|1,mid+1,r,L,R);
}
}
void update(int x,int l,int r,int L,int R,int k)
{
if(L<=l&&r<=R)
{
a[x].lazy+=k;
a[x].val+=k*(r-l+1);
}
else{
int mid=(l+r)>>1;
if(a[x].lazy) down(x,r-l+1);
if(L<=mid) update(x<<1,l,mid,L,R,k);
if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
up(x);
}
}
int queryR(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
res=0;
query(1,1,n,id[top[x]],id[x]);
(ans+=res)%=Mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
res=0;
query(1,1,n,id[x],id[y]);
ans+=res;
return ans%Mod;
}
void updateR(int x,int y,int k)
{
k%=Mod;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,id[x],id[y],k);
}
int queryS(int x)
{
res=0;
query(1,1,n,id[x],id[x]+size[x]-1);
return res;
}
void updateS(int x,int k){update(1,1,n,id[x],id[x]+size[x]-1,k);}
void dfs(int x,int father,int deep)
{
dep[x]=deep;
fa[x]=father;
size[x]=1;
int numson=-1;
for(int i=head[x];i;i=edge[i].next)
{
int qwq=edge[i].to;
if(qwq==father) continue;
dfs(qwq,x,deep+1);
size[x]+=size[qwq];
if(size[qwq]>numson)
son[x]=qwq,numson=size[qwq];
}
}
void dfs2(int x,int topN)
{
id[x]=++dfn;
f[dfn]=x;
top[x]=topN;
if(!son[x]) return;
dfs2(son[x],topN);
for(int i=head[x];i;i=edge[i].next)
{
int qwq=edge[i].to;
if(qwq==fa[x]||qwq==son[x]) continue;
dfs2(qwq,qwq);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&root,&Mod);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1,x,y;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(root,0,1);
dfs2(root,root);
build(1,1,n);
while(m--)
{
int op,x,y,k;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&k);
updateR(x,y,k);
}
else if(op==2)
{
scanf("%d%d",&x,&y);
printf("%d\n",queryR(x,y));
}
else if(op==3)
{
scanf("%d%d",&x,&y);
updateS(x,y);
}
else
{
scanf("%d",&x);
printf("%d\n",queryS(x));
}
}
return 0;
}

浙公网安备 33010602011771号