luogu P3384 【模板】重链剖分
参考博客:https://www.cnblogs.com/ivanovcraft/p/9019090.html
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
const int maxn=1e5+;
struct edge
{
int next,to;
} e[maxn*];
int head[maxn],cnt;
struct node
{
int l,r,ls,rs,sum,lazy;
} a[maxn*];
int n,m,r,rt,mod;
int v[maxn];
int f[maxn];//f[u] 保存结点u的父亲节点
int d[maxn];//d[u] 保存结点u的深度值
int son[maxn];//son[u] 保存重儿子
int size[maxn];//size[u] 保存以u为根的子树节点个数
int top[maxn];//top[u] 保存当前节点所在链的顶端节点
int id[maxn];//id[u] 保存树中每个节点剖分以后的新编号(DFS的执行顺序)
int rk[maxn];//rk[u] 保存当前dfs标号在树中所对应的节点
void add(int x,int y)
{
e[++cnt].next=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs1(int x) //当前节点
{
size[x]=;
d[x]=d[f[x]]+;
for(int v,i=head[x]; i; i=e[i].next)
if((v=e[i].to)!=f[x])
{
f[v]=x;
dfs1(v);
size[x]+=size[v];//子节点的size已被处理,用它来更新父节点的size
if(size[son[x]]<size[v])
son[x]=v; //选取size最大的作为重儿子
}
}
void dfs2(int x,int tp)//当前节点、重链顶端
{
top[x]=tp;
id[x]=++cnt;//标记dfs序
rk[cnt]=x;//序号cnt对应节点u
if(son[x])
dfs2(son[x],tp);
/*我们选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
for(int v,i=head[x]; i; i=e[i].next)
if((v=e[i].to)!=f[x]&&v!=son[x])
dfs2(v,v);//一个点位于轻链底端,那么它的top必然是它本身
}
inline void pushup(int x)
{
a[x].sum=(a[a[x].ls].sum+a[a[x].rs].sum)%mod;
}
void build(int l,int r,int x)
{
if(l==r)
{
a[x].sum=v[rk[l]],a[x].l=a[x].r=l;
return;
}
int mid=l+r>>;
a[x].ls=cnt++,a[x].rs=cnt++;
build(l,mid,a[x].ls),build(mid+,r,a[x].rs);
a[x].l=a[a[x].ls].l,a[x].r=a[a[x].rs].r;
pushup(x);
}
inline int len(int x)
{
return a[x].r-a[x].l+;
}
inline void pushdown(int x)
{
if(a[x].lazy)
{
int ls=a[x].ls,rs=a[x].rs,lz=a[x].lazy;
(a[ls].lazy+=lz)%=mod,(a[rs].lazy+=lz)%=mod;
(a[ls].sum+=lz*len(ls))%=mod,(a[rs].sum+=lz*len(rs))%=mod;
a[x].lazy=;
}
}
void update(int l,int r,int c,int x)
{
if(a[x].l>=l&&a[x].r<=r)
{
(a[x].lazy+=c)%=mod,(a[x].sum+=len(x)*c)%=mod;
return;
}
pushdown(x);
int mid=a[x].l+a[x].r>>;
if(mid>=l)
update(l,r,c,a[x].ls);
if(mid<r)
update(l,r,c,a[x].rs);
pushup(x);
}
int query(int l,int r,int x)
{
if(a[x].l>=l&&a[x].r<=r)
return a[x].sum;
pushdown(x);
int mid=a[x].l+a[x].r>>,tot=;
if(mid>=l)
tot+=query(l,r,a[x].ls);
if(mid<r)
tot+=query(l,r,a[x].rs);
return tot%mod;
}
inline int sum(int x,int y)
{
int ret=;
while(top[x]!=top[y])//两点不在同一条重链
{
if(d[top[x]]<d[top[y]])
swap(x,y);
(ret+=query(id[top[x]],id[x],rt))%=mod;//线段树区间求和,处理这条重链的贡献
x=f[top[x]];//将x设置成原链头的父亲结点,走轻边,继续循环
}
//循环结束,两点位于同一重链上,但两点不一定为同一点,所以我们还要统计这两点之间的贡献
if(id[x]>id[y])
swap(x,y);
return (ret+query(id[x],id[y],rt))%mod;
}
inline void updates(int x,int y,int c)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])
swap(x,y);
update(id[top[x]],id[x],c,rt);
x=f[top[x]];
}
if(id[x]>id[y])
swap(x,y);
update(id[x],id[y],c,rt);
}
signed main()
{
scanf("%lld%lld%lld%lld",&n,&m,&r,&mod);
for(int i=; i<=n; i++)
scanf("%lld",&v[i]);
for(int x,y,i=; i<n; i++)
{
scanf("%lld%lld",&x,&y);
add(x,y),add(y,x);
}
cnt=,dfs1(r),dfs2(r,r);
cnt=,build(,n,rt=cnt++);
for(int op,x,y,k,i=; i<=m; i++)
{
scanf("%lld",&op);
if(op==)//将树从 xx 到 yy 结点最短路径上所有节点的值都加上 zz
{
scanf("%lld%lld%lld",&x,&y,&k);
updates(x,y,k);
}
else if(op==)//求树从 xx 到 yy 结点最短路径上所有节点的值之和。
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",sum(x,y));
}
else if(op==)//将以 xx 为根节点的子树内所有节点值都加上 zz
{
scanf("%lld%lld",&x,&y);
update(id[x],id[x]+size[x]-,y,rt);
}
else//以 xx 为根节点的子树内所有节点值之和
{
scanf("%lld",&x);
printf("%lld\n",query(id[x],id[x]+size[x]-,rt));
}
}
return ;
}
luogu P3384 【模板】重链剖分的更多相关文章
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- 【luogu P3384 树链剖分】 模板
题目链接:https://www.luogu.org/problemnew/show/P3384 诶又给自己留了个坑..不想写线段树一大理由之前的模板变量名太长 #include <cstdio ...
- Luogu - P3384 树链剖分 [挂模板专用]
题意:请码个树剖模板支持子树区间加/查询和路径加/查询 纯练手 盲敲技能++ 以后网络赛复制模板速度++++ 对链操作时注意方向 #include<bits/stdc++.h> #defi ...
- 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)
2020/4/30 15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...
- 洛谷 - P2146 - 软件包管理器 - 重链剖分
https://www.luogu.org/problem/P2146 继续重链剖分. 这里好像很好懂,每次安装软件就区间改值赋值整个路径是1,然后比较前后的sum值变化就可以了.事实上后一次的sum ...
- Luogu P2742 模板-二维凸包
Luogu P2742 模板-二维凸包 之前写的实在是太蠢了.于是重新写了一个. 用 \(Graham\) 算法求凸包. 注意两个向量 \(a\times b>0\) 的意义是 \(b\) 在 ...
- luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)
luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...
- Luogu P3384 【【模板】树链剖分】
转载请注明出处,部分内容引自banananana大神的博客 ~~别说你不知道什么是树~~╮(─▽─)╭(帮你百度一下) 先来回顾两个问题:1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模 ...
- 【模板】树链剖分(Luogu P3384)
题目描述 众所周知 树链剖分是个好东西QWQ 也是一个代码量破百的算法 基本定义 树路径信息维护算法. 将一棵树划分成若干条链,用数据结构去维护每条链,复杂度为O(logN). 其实本质是一些数据结 ...
随机推荐
- linux下的特殊模式
单用户模式 ubuntu 16.04 单用户操作 1.重启操作系统,BIOS引导过后一直按住shift,出现GUN Grub菜单: 2.选择Advanced options for Ubuntu选项回 ...
- Git详解之特殊工具
前言 现在,你已经学习了管理或者维护 Git 仓库,实现代码控制所需的大多数日常命令和工作流程.你已经完成了跟踪和提交文件的基本任务,并且发挥了暂存区和轻量级的特性分支及合并的威力. 接下来你将领略到 ...
- Shell与进程
查看当前运行的进程 名称: ps 使用权限: 所有使用者 使用方式: ps [options] [--help] 说明: 显示瞬间行程 (process) 的动态 参数: ps的参数非常多, 在此仅列 ...
- 使用 web3D 技术的风力发电场展示
前言 风能是一种开发中的洁净能源,它取之不尽.用之不竭.当然,建风力发电场首先应考虑气象条件和社会自然条件.近年来,我国海上和陆上风电发展迅猛.海水.陆地为我们的风力发电提供了很好地质保障.正是 ...
- Linux学习笔记-配置阿里云yum源
进入目录:cd /etc/yum.repos.d 备份:mkdir repobak mv *.repo repobak/ 下载CentOS-Base.repo 到路径/etc/yum.repos.d/ ...
- python 中的反斜杠匹配的问题
关于反斜杠的匹配问题可以参考: https://www.cnblogs.com/mzc1997/p/7689235.html 文章中提出了两个概念: 字符串转义和正则转义,我觉得是理解反斜杠的关键所在 ...
- Codeforces_818
A.winners总数为(k+1)diplomas. #include<bits/stdc++.h> using namespace std; long long n,k; int mai ...
- 三、Mongodb Java中的使用
添加maven依赖 <!--mongodb 驱动--> <dependency> <groupId>org.mongodb</groupId> < ...
- Part2-求AX=b的最优解
自己一边听课一边记得,参考网上广为流传的那本<MIT线性代数笔记>,转成Latex上传太麻烦,直接截图上传了,需要电子版的可以私信我.
- Linux 配置ip 子接口 多网卡绑定
linux系统配置ip地址,图形化界面略过,这里只介绍文本行.做以下设置注意是否有此权限 查看当前路由及网关信息: [root@localhost ~]# netstat -r Kernel IP r ...