树链剖分详解 luoguP3384【模板】树链剖分

mac2022-07-05  13

一:用处

  对一棵树分成几条链,把树形变为线性,减少处理难度  需要处理的问题:

    1.将树从x到y结点最短路径上所有节点的值都加上z

    2.求树从x到y结点最短路径上所有节点的值之和

    3.将以x为根节点的子树内所有节点值都加上z

    4.求以x为根节点的子树内所有节点值之和

二:相关概念:

1.重儿子:对于每一个非叶子节点,它的儿子中以那个儿子为根的子树节点数(包括自身)最大的儿子为该节点的重儿子

2.轻儿子:非重儿子

3.重边:一个父节点与其重儿子的连边

4.轻边:非重边

5.重链:相邻重边相连形成的链

tips:叶子结点若为轻儿子,则自成一条长度为1的链

  重链以轻儿子或根节点为起点

三:常规操作

1.预处理

(1)dfs1:

处理:

  各点深度;  各点重儿子编号; 各点最大子树大小 ;各点父亲

代码:

void dfs1(int now,int fa,int deep) { siz[now]=1; fat[now]=fa; dep[now]=deep; zs=-1; for(int i=head[now];i;i=nxt[i]) { if(to[i]==now) continue; //别忘了 dfs1(to[i],now,deep+1); siz[now]+=siz[to[i]]; if(siz[to[i]]>zs)//处理重儿子 zhoson[now]=to[i],zs=siz[to[i]]; } }

 

(2)dfs2

处理:

   标记每个点的新编号(线段树中编号)

   赋值每个点的初始值到新编号上

   处理每个点所在链的顶端

   处理每条链

顺序规定:先重后轻

代码:

 

void dfs2(int now,int top) { tp[now]=top; id[now]=++cnt; wt[cnt]=w[x]; if(!zhoson[now]) return; dfs2(zhoson[now],top); for(int i=head[now];i;i=nxt[i]) { if(to[i]==fat[now]||to[i]==zhoson[now]) continue; dfs2(to[i],to[i]); } }

 2.功能实现

  1.查询两点间距离

  方法:每次选定两点所在链中深度较大的,加上它到其链起点的权值,然后跳到链起点的父节点重复操作,直至两点在同一条链上。

  

int qiurange(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); res=0; query(1,1,n,tid[top[x]],tid[x]); ans=(ans+res)%mod; x=fat[top[x]]; } if(deep[x]>deep[y]) swap(x,y); res=0; query(1,1,n,tid[x],tid[y]); ans=(ans+res)%mod; return ans; }

  2.两点间路径修改:

  同1,反复跳并update(线段树)

void uprange(int x,int y,int k) { k%=mod; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); update(1,1,n,tid[top[x]],tid[x],k); x=fat[top[x]]; } if(deep[x]>deep[y]) swap(x,y); update(1,1,n,tid[x],tid[y],k); }

3.子树修改

上边提到过,子树中节点的编号是连续的,因此在线段树上也是一段连续的区间,相当于线段树区间修改

void updSon(int x,int k) { update(1,1,n,tid[x],tid[x]+siz[x]-1,k); }

4.子树查询

只要直接维护即可。(区间的起点是该子树根节点,大小是子树大小)

int qSon(int x) { res=0; query(1,1,n,tid[x],tid[x]+siz[x]-1); return res; }

完整代码如下,除了上面的部分还要有线段树的基本操作函数(因此码量感人)


 

#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define maxn 100005 #define mid (l+r>>1) #define len (r-l+1) #define ls id<<1 #define rs id<<1|1 using namespace std; int cnt,head[maxn],nxt[maxn << 1],to[maxn << 1]; int w[maxn],wt[maxn],tidnum,siz[maxn],deep[maxn],son[maxn],fat[maxn],tid[maxn],top[maxn]; int a[maxn << 2],laz[maxn << 2]; int res=0,n,m,r,mod; void addedge(int x,int y) { to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; } void pushdown(int rt,int l,int r) { (laz[rt<<1]+=laz[rt]) %= mod; (laz[rt<<1|1]+=laz[rt]) %= mod; a[rt<<1]+=laz[rt]*(mid - l + 1); a[rt<<1|1]+=laz[rt]*(r - mid); a[rt<<1]%=mod; a[rt<<1|1]%=mod; laz[rt]=0; } void build(int id,int l,int r) { if(l==r) { a[id]=wt[l]; if(a[id]>mod) a[id]%=mod; return; } build(ls,l,mid); build(rs,mid+1,r); a[id]=(a[id<<1]+a[id<<1|1])%mod; } void query(int id,int l,int r,int tol,int tor) { if(tol<=l&&r<=tor) { res+=a[id]; res%=mod; return; } else { if(laz[id]) pushdown(id,l,r); if(tol<=mid) query(ls,l,mid,tol,tor); if(tor>mid) query(rs,mid+1,r,tol,tor); } } void update(int id,int l,int r,int tol,int tor,int k) { if(tol<=l&&r<=tor) { laz[id]+=k; a[id]+=k*len; a[id] %= mod; laz[id] %= mod; } else { if(laz[id]) pushdown(id,l,r); if(tol<=mid) update(ls,l,mid,tol,tor,k); if(tor>mid) update(rs,mid+1,r,tol,tor,k); a[id]=(a[id<<1]+a[id<<1|1])%mod; } } int qiurange(int x,int y) { int ans=0; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); res=0; query(1,1,n,tid[top[x]],tid[x]); ans=(ans+res)%mod; x=fat[top[x]]; } if(deep[x]>deep[y]) swap(x,y); res=0; query(1,1,n,tid[x],tid[y]); ans=(ans+res)%mod; return ans; } void uprange(int x,int y,int k) { k%=mod; while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) swap(x,y); update(1,1,n,tid[top[x]],tid[x],k); x=fat[top[x]]; } if(deep[x]>deep[y]) swap(x,y); update(1,1,n,tid[x],tid[y],k); } int qSon(int x) { res=0; query(1,1,n,tid[x],tid[x]+siz[x]-1); return res; } void updSon(int x,int k) { update(1,1,n,tid[x],tid[x]+siz[x]-1,k); } void dfs1(int x,int f,int deeep) { deep[x]=deeep; fat[x]=f; siz[x]=1; int maxson=-1; for(int i=head[x];i;i=nxt[i]) { int y=to[i]; if(y==f) continue; dfs1(y,x,deeep+1); siz[x]+=siz[y]; if(siz[y]>maxson) son[x]=y,maxson=siz[y]; } } void dfs2(int id,int tp) { tid[id]=++tidnum; wt[tidnum]=w[id]; top[id]=tp; if(!son[id]) return; dfs2(son[id],tp); for(int i=head[id];i;i=nxt[i]) { if(to[i]==fat[id]||to[i]==son[id]) continue; dfs2(to[i],to[i]); } } int main() { scanf("%d%d%d%d",&n,&m,&r,&mod); for(int i=1;i<=n;i++) scanf("%d",&w[i]); for(int i=1;i<n;i++) { int a,b; scanf("%d%d",&a,&b); addedge(a,b); addedge(b,a); } dfs1(r,0,1); dfs2(r,r); build(1,1,n); while(m--) { int t,x,y,z; scanf("%d",&t); if(t==1) { scanf("%d%d%d",&x,&y,&z); uprange(x,y,z); } else if(t==2) { scanf("%d%d",&x,&y); printf("%d\n",qiurange(x,y)); } else if(t==3) { scanf("%d%d",&x,&y); updSon(x,y); } else { scanf("%d",&x); printf("%d\n",qSon(x)); } } return 0; }

 

转载于:https://www.cnblogs.com/charlesss/p/10474190.html

最新回复(0)