如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

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

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

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

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

--by洛谷



一听名字就知道是模板;

有关树链剖分的内容

对子树操作,可理解为对dfs序上fa开头长度为子树size的区间操作;

代码如下:

 #include<cstdio>
using namespace std;
int n,m,r,L,R;
int p,Z;
int dis[];
int ltree[];
int lz[];
int dep[],fa[],hine[],size[];
int top[],a[],rank[];
struct ss{
int to,next;
}x[];
int first[],num;
void build(int ,int );
void dfs_1(int );
void dfs_2(int ,int );
void up(int );
void down(int ,int ,int );
void builine(int ,int ,int );
void swap(int&,int&);
void work1(int );
void work2(int );
void add(int ,int ,int );
int sum(int ,int ,int );
int main()
{
int i,j,k;
scanf("%d%d%d%d",&n,&m,&r,&p);
for(i=;i<=n;i++)
scanf("%d",&dis[i]),dis[i]%=p,hine[i]=i;
for(i=;i<=n-;i++){
scanf("%d%d",&j,&k);
build(j,k);
build(k,j);
}
dep[r]=;
dfs_1(r);
num=;
dfs_2(r,r);
num=;
builine(,n,);
for(i=;i<=m;i++){
scanf("%d",&j);
if(j<=)work1(j);
else work2(j-);
}
}
void build(int f,int t){
x[++num].next=first[f];
x[num].to=t;
first[f]=num;
}
void dfs_1(int now){
int j=first[now];
while(j){
if(!dep[x[j].to]){
dep[x[j].to]=dep[now]+;
fa[x[j].to]=now;
dfs_1(x[j].to);
size[now]+=size[x[j].to];
if(hine[now]==now||size[x[j].to]>size[hine[now]])
hine[now]=x[j].to;
}
j=x[j].next;
}
size[now]++;
}
void dfs_2(int now,int top_now){
int j=first[now];
top[now]=top_now;
a[++num]=now;
rank[now]=num;
if(hine[now]!=now)
dfs_2(hine[now],top_now);
while(j){
if(dep[x[j].to]==dep[now]+&&x[j].to!=hine[now])
dfs_2(x[j].to,x[j].to);
j=x[j].next;
}
}
void up(int nu){
ltree[nu]=ltree[nu<<]+ltree[nu<<|];
}
void down(int l,int r,int nu){
if(!lz[nu])return ;
int mid=(l+r)>>;
lz[nu<<]=(lz[nu<<]+lz[nu])%p;
lz[nu<<|]=(lz[nu<<|]+lz[nu])%p;
ltree[nu<<]=(ltree[nu<<]+lz[nu]*(mid-l+))%p;
ltree[nu<<|]=(ltree[nu<<|]+lz[nu]*(r-mid))%p;
lz[nu]=;
}
void builine(int l,int r,int nu){
if(l==r){
ltree[nu]=dis[a[++num]];
return;
}
int mid=(l+r)>>;
builine(l,mid,nu<<);
builine(mid+,r,nu<<|);
up(nu);
}
void swap(int&a,int&b){
int c=a;a=b;b=c;
}
void work1(int x){
int u,v,ans=;
scanf("%d%d",&u,&v);
if(x==)scanf("%d",&Z);
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]])
L=rank[top[u]],R=rank[u],u=fa[top[u]];
else
L=rank[top[v]],R=rank[v],v=fa[top[v]];
if(x==)
add(,n,);
else
ans=(ans+sum(,n,))%p;
}
// if(u!=v){
if(dep[u]>dep[v])
swap(u,v);
L=rank[u];R=rank[v];
if(x==)
add(,n,);
else
ans=(ans+sum(,n,))%p;
// }
if(x==)
printf("%d\n",ans);
}
void work2(int x){
int ans=,i;
scanf("%d",&i);
L=rank[i];R=L+size[i]-;
if(x==)scanf("%d",&Z);
if(x==)
add(,n,);
else
ans=(ans+sum(,n,))%p,printf("%d\n",ans);
}
void add(int l,int r,int nu){
if(L<=l&&r<=R){
ltree[nu]=(ltree[nu]+(r-l+)*Z)%p;
lz[nu]=(lz[nu]+Z)%p;
return ;
}
int mid=(l+r)>>;
down(l,r,nu);
if(L<=mid)
add(l,mid,nu<<);
if(R>mid)
add(mid+,r,nu<<|);
up(nu);
}
int sum(int l,int r,int nu){
if(L<=l&&r<=R)
return ltree[nu];
int mid=(l+r)>>,ans=;
down(l,r,nu);
if(L<=mid)
ans=(ans+sum(l,mid,nu<<))%p;
if(R>mid)
ans=(ans+sum(mid+,r,nu<<|))%p;
return ans;
}

祝AC哟!

洛谷P3384 树链剖分的更多相关文章

  1. 洛谷 P3384 树链剖分(模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  2. 洛谷 P3384树链剖分 题解

    题面 挺好的一道树剖模板: 首先要学会最模板的树剖: 然后这道题要注意几个细节: 初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root; 在线段树上 ...

  3. 洛谷 [P3384] 树链剖分 模版

    支持各种数据结构上树,注意取膜. #include <iostream> #include <cstring> #include <algorithm> #incl ...

  4. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  5. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  6. 洛谷P2146 树链剖分

    题意 思路:直接树链剖分,用线段树维护即可,算是树剖的经典题目吧. 代码: #include <bits/stdc++.h> #define ls(x) (x << 1) #d ...

  7. 【树链剖分】洛谷P3384树剖模板

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  8. 洛谷树剖模板题 P3384 | 树链剖分

    原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...

  9. P3384——树链剖分&&模板

    题目描述 链接 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: ...

随机推荐

  1. 如何在CentOS 7上使用vsftpd(FTP)的配置文件介绍

    vsftpd.conf - vsftpd的配置文件. 描述 vsftpd.conf可用于控制vsftpd行为的各个方面. 默认情况下,vsftpd在/etc/vsftpd.conf位置查找此文件. 但 ...

  2. Express-及中间件的简单理解

    Express Express 是一个基于node平台,保持最小规模的灵活的 Node.js Web 应用程序开发框架,在Node.js基础上扩展对了web应用开发所需要的基础功能为 Web 和移动应 ...

  3. 关于在JS中AJAX导致跨域问题的解决

    在部署一个原声的前端项目的时候,请求该服务器后端接口时发现出现了CORS跨域的问题,但是服务端已经做了同源策略的兼容,常见问题,遂记录. 报错信息: XMLHttpRequest cannot loa ...

  4. 架构师养成记--20.netty的tcp拆包粘包问题

    问题描述 比如要发ABC DEFG HIJK 这一串数据,其中ABC是一个包,DEFG是一个包,HIJK是一个包.由于TCP是基于流发送的,所以有可能出现ABCD EFGH 这种情况,那么ABC和D就 ...

  5. CentOS 7 安装方式汇总

    U盘安装 通过U盘安装 CentOS 的过程和安装Windows非常相似,首先将 CentOS 镜像文件刻录到U盘(或者光盘),设置固件(BIOS或者UEFI)从U盘启动,然后逐步设置即可. 使用 V ...

  6. PCA简单实现

    ''' 总结一下PCA的算法步骤: 设有m条n维数据. 1)将原始数据按列组成n行m列矩阵X 2)将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值 3)求出协方差矩阵C=1/m*(XX ...

  7. Linux 命令 su 和 sudo 比较

    su : 可以用来切换到任何用户,但是要求输入目标用户的密码 比如:su - su - root (等价 su -) su - user su root 与 su - root 的区别在于,后者不切换 ...

  8. css3基础下

    box-shadow:0 5px 5px rgba(0,0,0,0.5) 文本 text-shadow:5px 5px 4px green; word-wrap: 背景: background:#ff ...

  9. 深入分析java web技术内幕目录一览

    Web请求过程 如何发起请求:browser,httpclient http解析:chrome ,cache Dns域名解析:域名缓存 cdn:负载,动态加速,回源 Java I/O I/0类库的基本 ...

  10. Spring源码深度解析系列-----------org.springframework.aop-3.0.6.RELEASE

    Spring源码深度解析系列-----------org.springframework.aop-3.0.6.RELEASE