洛谷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: ...
随机推荐
- QuantLib 金融计算——QuantLib 入门
目录 QuantLib 金融计算--QuantLib 入门 简介 主要功能 安装与使用 学习指南 The HARD Way The EASY Way QuantLib 金融计算--QuantLib 入 ...
- Kettle 系列随笔
1.Kettle导入数据到Hive 出现多余的几行全部是null值的情况 2.Kettle根据表输入的SQL脚本返回创建表的SQL脚本 3.Kettle 行列互换之——行转列(多列数据合并成一列变为多 ...
- Python【每日一问】17
问: [基础题]:简述Python的异常处理机制[提高题]:请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%2 ...
- nodejs(四) --- cluster模块详解
什么是cluster模块,为什么需要cluster模块? cluster在英文中有集.群的意思. nodejs默认是单进程的,但是对于多核的cpu来说, 单进程显然没有充分利用cpu,所以,node ...
- dubbo接口快速测试技巧
在分布式系统的开发中,用到了dubbo+zookeeper技术,最近遇到一个问题,产品上线后,我负责的模块出了问题,某个bean中某个字段的值一直为null,而这个bean是我调用注册在zookeep ...
- Linux 下使用yum 命令安装MySQL
Linux下使用yum安装MySQL,以及启动.登录和远程访问MySQL数据库. 1.yum安装mysql 1. 查看有没有安装包: yum list mysql* #移除已经安装的mysq ...
- WPF Binding(四种模式)
在使用Binding类的时候有4中绑定模式可以选择 BindingMode TwoWay 导致对源属性或目标属性的更改可自动更新对方.此绑定类型适用于可编辑窗体或其他完全交互式 UI 方案. OneW ...
- Eclipse空白包的显示和隐藏
Eclipse空白包的显示和隐藏 点击三角形, ,下拉 -> Customize View... -> Empty packages (勾选)
- Android studio应用导入源码错误This attribute must be localized
This attribute must be localized 产生原因: 多语言错误,源码中关于语言的显示不能直接赋值,而是需要通过xml来实现: 例如 <TextView android: ...
- JAVA-1NIO概述
注意: 转载自并发编程网 – ifeve.com本文链接地址: Java NIO系列教程(一) Java NIO 概述 JAVA-1NIO概述 Java NIO 由以下几个核心部分组成: Channe ...