博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P3384 【模板】树链剖分
阅读量:5234 次
发布时间:2019-06-14

本文共 4078 字,大约阅读时间需要 13 分钟。

树链剖分 时间!!!!

首先要学会线段树。由于线段树是基本技能,所以不再此过多解释。

 

树链剖分操作如下

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

 

还有几个概念:重儿子,轻儿子,重链,轻链。

众所周知,以每一个节点为根节点下所成的树(语文技能崩溃)都有一个大小(节点的数量)

如果有一个儿子体型(节点数)在所有兄弟姐妹中最大,那么这个儿子就是这个节点的重儿子;

其他的儿子都是轻儿子。

重边就是每两个重儿子之间的边(手拉手,我们都是重儿子);轻边就是剩下的;

重链就是相邻的每个重边连起来的链,包括一条端点重儿子和轻儿子之间的边,也就是所有重链以一个轻儿子开始;

 

看完定义该干事了!!!

首先,处理dep[],fa[],siz[],son[]

 

void dfs1(int u,int fa){    f[u]=fa;//记录u节点的父亲     siz[u]=1;//子树大小,包括他自己     dep[u]=dep[fa]+1;//深度     for(int p=last[u];p;p=pre[p])    {        int v=other[p];        if(v==fa) continue;        dfs1(v,u);        siz[u]+=siz[v];        if(siz[v]>siz[son[u]]) son[u]=v;//记录重儿子         }}

second 新编,赋值,找头,先重再轻

因为先处理重儿子就会让重儿子之间的编号是连续的。

void dfs2(int u,int tp){    id[u]=++cnt;//重新编号     top[u]=tp;//这个点所在链的顶端     b[cnt]=a[u];//新编号赋值    if(!son[u]) return ;//no son    dfs2(son[u],tp);    for(int p=last[u];p;p=pre[p])    {        int v=other[p];        if(v==son[u]||v==f[u]) continue;        dfs2(v,v);//对于每一个轻儿子都有一条从它自己开始的链     }    }

 

third 套用线段树。

 

代码:

#include
#include
#include
using namespace std;const int maxn=100050;int n,m,s,mo,a[maxn];int pre[maxn*2],other[maxn*2],last[maxn],l;int f[maxn],siz[maxn],dep[maxn],son[maxn];int id[maxn],cnt,top[maxn],b[maxn];void add(int x,int y){ l++; pre[l]=last[x]; last[x]=l; other[l]=y;}//下面是线段树 struct tree{ int l,r; int sum,lazy;}t[4*maxn];//四倍,前人的经验 void build(int x,int l,int r)//建树 { t[x].l=l;t[x].r=r; if(l==r) { t[x].sum=b[l]; return ; } int mid=(l+r)>>1; build(2*x,l,mid); build(2*x+1,mid+1,r); t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;}void update(int x)//更新懒标签 { t[2*x].sum+=((t[2*x].r-t[2*x].l+1)*t[x].lazy)%mo; t[2*x+1].sum+=((t[2*x+1].r-t[2*x+1].l+1)*t[x].lazy)%mo; t[2*x].lazy+=t[x].lazy;t[2*x].lazy%=mo; t[2*x+1].lazy+=t[x].lazy;t[2*x+1].lazy%=mo; t[x].lazy=0;}void change(int x,int l,int r,int z)//改变值 { if(t[x].l==l&&t[x].r==r) { t[x].sum+=(t[x].r-t[x].l+1)*z; t[x].lazy+=z; return ; } if(t[x].lazy) update(x); int mid=(t[x].l+t[x].r)>>1; if(r<=mid) change(2*x,l,r,z); else if(l>mid) change(2*x+1,l,r,z); else { change(2*x,l,mid,z); change(2*x+1,mid+1,r,z); } t[x].sum=(t[2*x].sum+t[2*x+1].sum)%mo;}int query(int x,int l,int r)//查询区间和 { if(t[x].l==l&&t[x].r==r) { return t[x].sum; } if(t[x].lazy) update(x); int mid=(t[x].l+t[x].r)>>1; if(r<=mid) return query(2*x,l,r); else if(l>mid) return query(2*x+1,l,r); else { return query(2*x,l,mid)+query(2*x+1,mid+1,r); }}//上面是线段树 void dfs1(int u,int fa){ f[u]=fa;//记录u节点的父亲 siz[u]=1;//子树大小,包括他自己 dep[u]=dep[fa]+1;//深度 for(int p=last[u];p;p=pre[p]) { int v=other[p]; if(v==fa) continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[v]>siz[son[u]]) son[u]=v;//记录重儿子 }}void dfs2(int u,int tp){ id[u]=++cnt;//重新编号 top[u]=tp;//这个点所在链的顶端 b[cnt]=a[u];//新编号赋值 if(!son[u]) return ;//no son dfs2(son[u],tp); for(int p=last[u];p;p=pre[p]) { int v=other[p]; if(v==son[u]||v==f[u]) continue; dfs2(v,v);//对于每一个轻儿子都有一条从它自己开始的链 } }void tchange(int x,int y,int z){ z%=mo; while(top[x]!=top[y])//如果不在一条链上 { if(dep[top[x]]
dep[y]) swap(x,y);//找到深度浅的那个 change(1,id[x],id[y],z);//最后一条链加z }int tcha(int x,int y){ int ans=0; while(top[x]!=top[y]) { if(dep[top[x]]
dep[y]) swap(x,y); ans+=query(1,id[x],id[y]); ans%=mo; return ans;}void changeson(int x,int z){ change(1,id[x],id[x]+siz[x]-1,z);//新编节点中每个节点和儿子们是连续的多么重要 }int chason(int x){ return query(1,id[x],id[x]+siz[x]-1);}int main(){ scanf("%d%d%d%d",&n,&m,&s,&mo); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i

 

刚学会,理解还是不太到位,欢迎指正。

 

 

 

 

 

 

 

温馨提示(放在最后坑你们):每个加减计算都要取模。。。。。。

 

转载于:https://www.cnblogs.com/WHFF521/p/11070147.html

你可能感兴趣的文章
iOS UICollectionView 入门 07 点击cell放大图片
查看>>
Android SystemUI源代码分析和修改
查看>>
tomcat 1.支持jsp和servlets的Web服务器 2.还是一个Servlet和JSP容器
查看>>
js比较函数
查看>>
微信小程序wx.showLoading
查看>>
小学生作文妙语(超级超级搞笑版!!!!!!!!!)
查看>>
数据仓库基础(四)ODS、元数据
查看>>
template-string
查看>>
团队任务个人博客--20160426
查看>>
MyBatis对不同数据库的主键生成策略
查看>>
velocity语法
查看>>
Android之SqlLite数据库使用
查看>>
多物体中添加透明度的显示
查看>>
zookeeper(1)——zookeeper服务器集群搭建配置
查看>>
XAF 如何实现ListView单元格批量更改?
查看>>
MySQL备份
查看>>
如何让你的iPhone程序支持多语言环境(本地化)
查看>>
NPM 使用
查看>>
python——函数和过程的区别
查看>>
C语言深度学习——第一天
查看>>