Luogu - P3384 树链剖分 [挂模板专用]
题意:请码个树剖模板支持子树区间加/查询和路径加/查询
纯练手
盲敲技能++
以后网络赛复制模板速度++++
对链操作时注意方向
#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define println(a) printf("%lld\n",(ll)a)
using namespace std;
const int MAXN = 2e5+11;
typedef long long ll;
ll MOD;
ll read(){
ll x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN],tot; ll cost[MAXN<<1];
void add(int u,int v,ll w=0){
to[tot]=v;
cost[tot]=w;
nxt[tot]=head[u];
head[u]=tot++;
}
int size[MAXN],dfn[MAXN],dfned[MAXN],pre[MAXN],p[MAXN],son[MAXN],dep[MAXN],top[MAXN],CLOCK;
void init(){
memset(head,-1,sizeof head);
memset(son,0,sizeof son);
tot=CLOCK=0;
}
void dfs(int u,int fa,int d){
p[u]=fa; dep[u]=d; size[u]=1;
son[u]=top[u]=0;
for(int i=head[u];~i;i=nxt[i]){
int v=to[i];
if(v==fa) continue;
dfs(v,u,d+1);
size[u]+=size[v];
if(size[v]>size[son[u]]){
son[u]=v;
}
}
}
void dfs2(int u,int tp){
top[u]=tp;
dfn[u]=++CLOCK;
pre[CLOCK]=u;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];~i;i=nxt[i]){
int v=to[i];
if(v==p[u]||v==son[u]) continue;
dfs2(v,v);
}
dfned[u]=CLOCK;
}
int a[MAXN];
struct ST{
ll sum[MAXN<<2];
int lazy[MAXN<<2];
#define lc o<<1
#define rc o<<1|1
void pu(int o){
sum[o]=sum[lc]+sum[rc];
if(sum[o]>=MOD) sum[o]%=MOD;
}
void build(int o,int l,int r){
sum[o]=lazy[o]=0;
if(l==r){
sum[o]=a[pre[l]]; //!!
return;
}
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pu(o);
}
void pd(int o,int l,int r){
if(lazy[o]){
int mid=l+r>>1;
sum[lc]+=(ll)(mid-l+1)*lazy[o];
sum[rc]+=(ll)(r-mid)*lazy[o];
if(sum[lc]>MOD) sum[lc]%=MOD;
if(sum[rc]>MOD) sum[rc]%=MOD;
lazy[lc]+=lazy[o];
lazy[rc]+=lazy[o];
lazy[o]=0;
}
}
void update(int o,int l,int r,int L,int R,ll v){
if(L<=l&&r<=R){
sum[o]+=(ll)(r-l+1)*v;
if(sum[o]>=MOD) sum[o]%=MOD;
lazy[o]+=v;
return;
}
pd(o,l,r);
int mid=l+r>>1;
if(L<=mid) update(lc,l,mid,L,R,v);
if(R>mid) update(rc,mid+1,r,L,R,v);
pu(o);
}
ll query(int o,int l,int r,int L,int R){
if(L<=l&&r<=R){
return sum[o];
}
pd(o,l,r);
int mid=l+r>>1;
ll ans=0;
if(L<=mid) ans+=query(lc,l,mid,L,R);
if(R>mid) ans+=query(rc,mid+1,r,L,R);
return ans>=MOD?ans%MOD:ans;
}
}st;
void solve(int u,int v,int val,int op){
ll ans=0;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
if(op==2) ans+=st.query(1,1,CLOCK,dfn[top[u]],dfn[u]);
if(op==2&&ans>=MOD) ans%=MOD;
else st.update(1,1,CLOCK,dfn[top[u]],dfn[u],val);
u=p[top[u]];
}
//same link
if(dep[u]<dep[v]) swap(u,v);
if(op==2) ans+=st.query(1,1,CLOCK,dfn[v],dfn[u]);//att
if(op==2&&ans>=MOD) ans%=MOD;
else st.update(1,1,CLOCK,dfn[v],dfn[u],val);
if(op==2) println(ans%MOD);
}
int main(){
int n,m,rt;
while(cin>>n>>m>>rt>>MOD){
init();
rep(i,1,n) a[i]=read();
rep(i,1,n-1){
int u=read();
int v=read();
add(u,v);
add(v,u);
}
dfs(rt,-1,1); dfs2(rt,rt);
st.build(1,1,CLOCK);
while(m--){
int op=read();
if(op==1){
int u=read();
int v=read();
ll val=read();
solve(u,v,val,op);
}else if(op==2){
int u=read();
int v=read();
solve(u,v,0,op);
}else if(op==3){
int x=read();
ll v=read();
int l=dfn[x],r=dfned[x];
st.update(1,1,CLOCK,l,r,v);
}else{
int x=read();
int l=dfn[x],r=dfned[x];
println(st.query(1,1,CLOCK,l,r)%MOD);
}
}
}
return 0;
}
Luogu - P3384 树链剖分 [挂模板专用]的更多相关文章
- 【luogu P3384 树链剖分】 模板
题目链接:https://www.luogu.org/problemnew/show/P3384 诶又给自己留了个坑..不想写线段树一大理由之前的模板变量名太长 #include <cstdio ...
- 洛谷 P3384 树链剖分(模板题)
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- 树链剖分(模板) 洛谷P3384
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...
- 洛谷P3384 树链剖分
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...
- P3384——树链剖分&&模板
题目描述 链接 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: ...
- 洛谷树剖模板题 P3384 | 树链剖分
原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...
- 【树链剖分/倍增模板】【洛谷】3398:仓鼠找sugar
P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而 ...
- 洛谷 P3384树链剖分 题解
题面 挺好的一道树剖模板: 首先要学会最模板的树剖: 然后这道题要注意几个细节: 初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root; 在线段树上 ...
- 洛谷 [P3384] 树链剖分 模版
支持各种数据结构上树,注意取膜. #include <iostream> #include <cstring> #include <algorithm> #incl ...
随机推荐
- SQL 零碎点
1,插入数据后,返回主键ID值: INSERT INTO tablename (name) VALUES (@name);SELECT @@Identity; 使用 SELECT @@Identity ...
- Google-优秀移动站点设计10招
Google-优秀移动网站设计10招 1)添加一个醒目的搜索条:在移动终端上,人们希望能够快速找到自己需要的东西 2)把大表格拆分成小块:别搞一个长长的表格页面,上面包含各种输入框 3)允许用户匿名浏 ...
- IO引脚复用和映射
1.端口复用 这些外设包括ADC,DAC以及串口等等. 查找STM32F429数据手册可以找到相关IO口的复用功能引脚. 注意:除ADC和DAC要配置成模拟通道外,其他的所有外设都要配置成复用功能.
- SQLServer学习-- Microsoft SQL Server 2008 Management Studio Express
Microsoft SQL Server 2008 Management Studio Express is a free, integrated environment for accessing, ...
- Linux Crontab 任务管理工具命令以及示例
Crontab 是 Linux 平台下的一款用于循环执行例行任务的工具,Linux 系统由 cron (crond) 这个系统服务来控制任务 , Linux系统本来就有很多的计划任务需要启动 , 所以 ...
- Replication--分区+复制
1>配置订阅表使用分区,在发布的项目属性中设置"复制分区方案"和"复制索引分区方案"为true,然后初始化订阅 2>在发布数据库上修改发布属性 -- ...
- linux最基本命令
1.cd命令 这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如: cd /root/Docements # 切换到 ...
- Major OSL changes to catch up
flat_map optimization for runtime specialization: https://github.com/imageworks/OpenShadingLanguage/ ...
- Unit Vector Compression
Recently, I compared a few methods for compressing generic unit vectors. The method used in Cry Engi ...
- ANE打包心得
1 ane中的p12证书是fb或者flashide中生成的(例如air工程生成的p12),不是苹果账号的p12 2 打包bat中的 -platform 要和 extension.xml中的platfo ...