如题,已知一棵包含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. 为什么说 Gumroad 是一家 “失败” 的创业公司?

    Gumroad 是一家 "失败" 的创业公司. 创立于 2012 年,Gumroad 是一个面向创造者的电商平台.创始人 Sahil Lavingia,一名 19 岁的少年,Pin ...

  2. 苹果隐私条例更新:收集用户电话和 Email 数据

    简评:苹果现在会收集用户的电话和电子邮件,作为用户「信任评级」的一部分,我还是支持的,因为园长被黑产攻击 AppleID,直接刷爆了我的卡!但是在大环境看,隐私已经不存在了. Apple 最近悄悄为 ...

  3. graphviz画图与中文乱码等问题总结

    最近想写一些文档,画一些程序的逻辑图,用了vision,markdown等软件感觉不怎么好用,于是找到graphviz,这款强大的软件.下面介绍一些入门,还有自己在用的过程中遇到的问题 1.中文乱码的 ...

  4. jscover使用说明-总体说明

    1.总体说明 这个文档现在是完善和准确的,不管怎样,尽量去参考JSCoverage documentation. 1.1.介绍 JSCove是一个用来显示JavaScript项目代码覆盖率的工具,它是 ...

  5. CSS--浮动(float)布局

    浮动概述:浮动,指的是元素标签使用float属性.应用float属性的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止.浮动的本质是让文字围绕图片,但现在很多时候使用浮动进行布局 ...

  6. Linux文件索引节点相关概念

    一.  概念 1.  inode(index node)表中包含文件系统所有文件列表 一个节点 (索引节点)是在一个表项,包含有关文件的信息( 元数据 ),包括: 文件类型,权限,UID,GID 链接 ...

  7. 1091 N-自守数 (15 分)

    // 建一个判断函数,接受两个整形的变量,再通过循环按位判断相等与否,主体函数中调用被调函数,建立一个判断变量.#include <iostream> using namespace st ...

  8. 033-JsonUtils 工具类模板

    模板一:使用的是jackson package cn.e3mall.common.utils; import java.util.List; import com.fasterxml.jackson. ...

  9. JavaScript设计模式-16.装饰者模式(上)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. 深度学习(四) softmax函数

    softmax函数 softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类! 假设我们有一个数组,V,Vi表示V中的第i个元素,那么这个元素 ...