洛谷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: ...
随机推荐
- re 模块 常规方法使用
前情提要: re模块主要用于正则,用的好了秒杀一切匹配的规则,这里主要是介绍基本用法 一:元字符 1:\w 匹配字符,包含中文,数字或下划线 l ='早乙女露依 123 是我的 321 心目中的 22 ...
- leetcode-40-组合总和 II
题目描述: 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在每个组合中只 ...
- web测试需要注意几个非常重要的测试点
web测试需要注意几个非常重要的测试点 微软语言标准: 全角字符和半角字符都要使用一个空格分开 英文和数字直接要有空页面分辨率: 通常是计算机的默认分辨率,但是还是会有一些老式电脑存在1024*7 ...
- Java NIO学习与记录(三): Scatter&Gather介绍及使用
Scatter&Gather介绍及使用 上一篇知道了Buffer的工作机制,以及FileChannel的简单用法,这一篇介绍下 Scatter&Gather 1.Scatter(分散 ...
- Calibre 3.4版中,为epub书籍嵌入中文字体
1. 先把原版书籍epub文件添加到Calibre书库: 2. 书名上右键,选则 转换书籍 -> 逐个转换: 3. 在 界面外观 -> 字体 中,选择嵌入字体,在列表中选择中文字体,并勾选 ...
- Sublime Text 3插件收集
0.Package Control 这个是必须装的,就不多解释了 1.ConvertToUTF8 支持 GBK, BIG5, EUC-KR, EUC-JP, Shift_JIS 等编码的插件. 2.B ...
- JVectorMap地图插件.Net版开源
jVectorMap地图插件只要浏览器技术JavaScript.CSS,HTML,SVG或VML就可以浏览使用,不需要Flash或其他专有的浏览 器插件.所以jVectorMap在所有现代移动浏览器上 ...
- spring boot快速入门 1 :创建项目、 三种启动项目方式
准备工作: (转载)IDEA新建项目时,没有Spring Initializr选项 最近开始使用IDEA作为开发工具,然后也是打算开始学习使用spring boot. 看着博客来进行操作上手sprin ...
- DesUtils工具类
public final class DesUtils { private static final String DES = "DES"; private static fina ...
- 《Algorithms算法》笔记:元素排序(3)——洗牌算法
<Algorithms算法>笔记:元素排序(3)——洗牌算法 Algorithms算法笔记元素排序3洗牌算法 洗牌算法 排序洗牌 Knuth洗牌 Knuth洗牌代码 洗牌算法 洗牌的思想很 ...