题意:请码个树剖模板支持子树区间加/查询和路径加/查询

纯练手

盲敲技能++

以后网络赛复制模板速度++++

对链操作时注意方向

#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 树链剖分 [挂模板专用]的更多相关文章

  1. 【luogu P3384 树链剖分】 模板

    题目链接:https://www.luogu.org/problemnew/show/P3384 诶又给自己留了个坑..不想写线段树一大理由之前的模板变量名太长 #include <cstdio ...

  2. 洛谷 P3384 树链剖分(模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  3. 树链剖分(模板) 洛谷P3384

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...

  4. 洛谷P3384 树链剖分

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...

  5. P3384——树链剖分&&模板

    题目描述 链接 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: ...

  6. 洛谷树剖模板题 P3384 | 树链剖分

    原题链接 对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树 剩下的就和树剖一样了 #include< ...

  7. 【树链剖分/倍增模板】【洛谷】3398:仓鼠找sugar

    P3398 仓鼠找sugar 题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而 ...

  8. 洛谷 P3384树链剖分 题解

    题面 挺好的一道树剖模板: 首先要学会最模板的树剖: 然后这道题要注意几个细节: 初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root; 在线段树上 ...

  9. 洛谷 [P3384] 树链剖分 模版

    支持各种数据结构上树,注意取膜. #include <iostream> #include <cstring> #include <algorithm> #incl ...

随机推荐

  1. CentOS/RedHat安装Python3

    CentOS/RedHat安装Python3 摘自:https://blog.csdn.net/mvpboss1004/article/details/79377019 CentOS/RedHat默认 ...

  2. Fiddldr 教程之:HTTP协议详解(转)

    原文地址:http://www.cnblogs.com/TankXiao/archive/2012/02/13/2342672.html HTTP协议详解 当今web程序的开发技术真是百家争鸣,ASP ...

  3. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  4. js对象 1字符串对象2时间日期对象3数字对象

    1字符串对象  直接对字符操作 var str = "这,是,不,是,字,符,串";        //字符串转数组  字符串.split(分隔符)        var arr ...

  5. APUE(4)---文件和目录 (1)

    一.引言 上一章执行I/O的基本函数(打开文件.读文件和写文件),本章将描述文件系统的其他特征和文件的性质,我们将从stat函数开始,并逐个说明stat结构的每一个成员以了解文件的所有属性.在此过程中 ...

  6. Gym - 100989G (二分法)

    There are K hours left before Agent Mahone leaves Amman! Hammouri doesn't like how things are going ...

  7. CodeForces 877E Danil and a Part-time Job(dfs序+线段树)

    Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...

  8. javascript高级程序设计读书笔记----面向对象的程序设计

        创建对象   工厂模式 function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = ...

  9. PreTranslateMessage()函数捕获键盘按键消息

    01. PreTranslateMessage函数,常用于屏蔽MFC对话框中默认的Enter和ESC消息 函数原型:BOOL PreTranslateMessage(MSG* pMsg) 用法举例: ...

  10. Arduino I2C + 温湿度传感器HTS221

    主要特性 HTS221是意法半导体(STMicroelectronics)生产的小体积.数字式温湿度传感器IC.该IC目前在官网仍处在“评估”状态.其主要特性: 工作电压:1.7~3.6V 数据输出频 ...