洛谷P3384 树链剖分
如题,已知一棵包含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 树链剖分的更多相关文章
- 洛谷 P3384 树链剖分(模板题)
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- 洛谷 P3384树链剖分 题解
题面 挺好的一道树剖模板: 首先要学会最模板的树剖: 然后这道题要注意几个细节: 初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root; 在线段树上 ...
- 洛谷 [P3384] 树链剖分 模版
支持各种数据结构上树,注意取膜. #include <iostream> #include <cstring> #include <algorithm> #incl ...
- 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器
刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...
- 【树链剖分】洛谷P3379 树链剖分求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 洛谷P2146 树链剖分
题意 思路:直接树链剖分,用线段树维护即可,算是树剖的经典题目吧. 代码: #include <bits/stdc++.h> #define ls(x) (x << 1) #d ...
- 【树链剖分】洛谷P3384树剖模板
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- 洛谷树剖模板题 P3384 | 树链剖分
原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...
- P3384——树链剖分&&模板
题目描述 链接 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: ...
随机推荐
- 阿里云服务器之Tomcat环境搭建以及域名绑定
上一步主要主要讲解在服务器中建立自己的hexo博客环境,最后达到可以远程访问,以及远程git推送到github.这章主要讲解Tomcat环境的搭建,以及域名解析.到这里你的服务器以及可以被全世界的人民 ...
- 永久激活navicat_premium12.0,支持win32和64位
1.下载软件以及注册机 链接:https://pan.baidu.com/s/1NGc6YLsgMQRQYEwnGSU16Q 提取码:guno 2.根据自己的电脑位数安装对应的软件,傻瓜式安全(注 ...
- Springboot接口简单实现生成MySQL插入语句
Springboot接口简单实现调用接口生成MySQL插入语句 在实际测试中,有这样一个需求场景,比如:在性能压力测试中,可能需要我们事先插入数据库中一些相关联的数据. 我们在实际测试中,遇到问题,需 ...
- Linux系统NAT模式下设置网络网关
1.配置Vm网络编辑器 2.配置固定IP地址 命令:vi /etc/sysconfig/network-scripts/ifcfg-ens33 #下面内容直接复制进去,如果有重复的可以去除 TYPE= ...
- (原创推荐文章)kerberos服务器端与客户端
#环境 两台装centos7的虚拟机即可. kerberos服务器端与客户端各一台 (本文档推荐使用Typora软件观看) # 1.kerberos服务器端配置 ## 1.1安装配置Kerberos ...
- Safari 不能播放Video ,Chrome等可以 问题解决。
1 原因分析 https://www.zhihu.com/question/41818719 2 代码实现 1 注意点: 请求时 : header中 range 请求多少长度 代码要返回相应的长度 ...
- PXE+Kickstart 批量安装CentOS 7
安装之前 将需要安装 CentOS 的服务器与 PXE 服务器通过网络设备连接:PXE 服务器安装 CentOS,并且关闭firewalld.selinux,设置静态IP地址,本例设为10.0.0.1 ...
- (二)Audio子系统之new AudioRecord()
在上一篇文章<(一)Audio子系统之AudioRecord.getMinBufferSize>中已经介绍了AudioRecord如何获取最小缓冲区大小,接下来,继续分析AudioReco ...
- 关于 maven 打包直接运行的 fat jar (uber jar) 时需要包含本地文件系统第三方 jar 文件的问题
关于maven打包fat jar (uber jar) 时需要包含本地文件系统第三方jar文件的问题,今天折腾了一整天.最后还是用了spring boot来做.下面是几篇关于打包的有参考价值的文章,以 ...
- [Xamarin.Android] 結合Windows Azure與Google cloud message 來實現Push Notification (转帖)
這一篇要討論如何使用Xamarin.Android 整合GCM以及Windows Azure來實作Android手機上的推播通知服務. 這篇文章比較著重概念的部分,在開始讀這篇之前,也可以先參考一下X ...