#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> #define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
using namespace std;
const int maxn = ;
int P;
typedef long long ll; struct Edge {
int to, next;
}edges[maxn*];
int head[maxn], tot;
int n;
ll w[maxn];
int fa[maxn], son[maxn], siz[maxn], dep[maxn];
int top[maxn], id[maxn], rk[maxn], cnt;
// son[u]: u的重儿子
// top[u]: u所在链的顶端节点
//
// id[u]: 树链剖分后节点的新编号
// rk[u]: dfs编号对应的节点 rk[id[u]] = u
// cnt : dfs序 void add(int u, int v) {
edges[++tot].to = v;
edges[tot].next = head[u];
head[u] = tot;
} // 求fa, siz, dep, son
void dfs1(int u) {
siz[u] = ;
for(int i=head[u];i;i=edges[i].next) {
int v = edges[i].to;
if(v==fa[u]) continue; fa[v] = u;
dep[v] = dep[u] + ;
dfs1(v);
siz[u] += siz[v]; if(siz[v]>siz[son[u]])
son[u] = v;
}
} // 连接重链
void dfs2(int u, int topf) {
id[u] = ++cnt;
rk[cnt] = u; top[u] = topf;
if(!son[u])
return; dfs2(son[u], topf); // 重链先dfs,保证重链上各节点dfs序连续 for(int i=head[u];i;i=edges[i].next) {
int v = edges[i].to;
if(v!=fa[u] && v!=son[u]) // 不是重儿子,轻链
dfs2(v, v);
}
} /*
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
*/ ll sum[maxn*], lazy[maxn*]; void build(int rt, int l, int r) {
if(l!=r) {
int mid = (l+r)/;
build(lson);
build(rson);
sum[rt] = (sum[rt<<] + sum[rt<<|]) % P;
} else {
sum[rt] = w[rk[l]];
lazy[rt] = ;
}
}
void pushDown(int rt, int len) {
if(lazy[rt]) {
(sum[rt<<] += (len-(len>>)) * lazy[rt] % P) %= P;
(sum[rt<<|] += (len>>) * lazy[rt] % P) %= P; (lazy[rt<<] += lazy[rt]) %= P;
(lazy[rt<<|] += lazy[rt]) %= P;
lazy[rt] = ;
}
} void update(int rt, int l, int r, int L, int R, ll add) {
if(L<=l && R>=r) {
(lazy[rt] += add) %= P;
(sum[rt] += (r-l+)*add) %= P;
return;
} int mid = (l+r)/;
pushDown(rt, r-l+); if(L<=mid)
update(lson, L, R, add);
if(R>mid)
update(rson, L, R, add); sum[rt] = (sum[rt<<] + sum[rt<<|]) % P;
} ll query(int rt, int l, int r, int L, int R) {
if(L<=l && R>=r) return sum[rt]; ll res = ;
int mid = (l+r)/;
pushDown(rt, r-l+); if(L<=mid) res += query(lson, L, R) % P;
if(R>mid) res += query(rson, L, R) % P;
return res % P;
} // 操作1
void updatePath(int x, int y, ll z) {
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x, y);
update(, , n, id[top[x]], id[x], z);
x = fa[top[x]];
}
if(dep[x]>dep[y]) swap(x, y);
update(, , n, id[x], id[y], z);
} // 操作3
void updateSon(int x, ll z) {
update(, , n, id[x], id[x]+siz[x]-, z);
} // 操作2
ll queryPath(int x, int y) {
ll res = ;
while(top[x]!=top[y]) {
if(dep[top[x]]<dep[top[y]]) swap(x, y);
res = (res + query(, , n, id[top[x]], id[x])) % P;
x = fa[top[x]];
}
if(dep[x]>dep[y]) swap(x, y);
res = (res + query(, , n, id[x], id[y])) % P;
return res;
} // 操作4
ll qeurySon(int x) {
return query(, , n, id[x], id[x]+siz[x]-);
} int main() {
int M, R;
cin>>n>>M>>R>>P;
for(int i=;i<=n;i++) {
scanf("%lld", &w[i]);
}
for(int i=;i<n-;i++) {
int u, v;
scanf("%d %d", &u, &v);
add(u, v);
add(v, u);
} dfs1(R);
dfs2(R, R); build(, , n); while(M--) {
int op, x, y;
ll z;
scanf("%d", &op);
if(op==) {
scanf("%d %d %lld", &x, &y, &z);
updatePath(x, y, z);
} else if(op==) {
scanf("%d %d", &x, &y);
printf("%lld\n", queryPath(x, y));
} else if(op==) {
scanf("%d %lld", &x, &z);
updateSon(x, z);
} else {
scanf("%d", &x);
printf("%lld\n", qeurySon(x));
} }
return ;
}

树链剖分(模板) 洛谷P3384的更多相关文章

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

    洛谷P3384 #include <bits/stdc++.h> #define DBG(x) cerr << #x << " = " < ...

  2. 【树链剖分】洛谷P3384树剖模板

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

  3. 树链剖分( 洛谷P3384 )

    我们有时候遇到这样一类题目,让我们维护树上路径的某些信息,这个时候发现我们无法用线段树或者树状数组来维护这些信息,那么我们就有着一种新的数据结构,树剖:将一棵树划分成若干条链,用数据结构去维护每条链, ...

  4. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  5. 树链剖分【洛谷P4114】 Qtree1

    P4114 Qtree1 题目描述 给定一棵n个节点的树,有两个操作: CHANGE i ti 把第i条边的边权变成ti QUERY a b 输出从a到b的路径中最大的边权,当a=b的时候,输出0 码 ...

  6. 树链剖分【洛谷P2590】 [ZJOI2008]树的统计

    P2590 [ZJOI2008]树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把 ...

  7. 树链剖分【洛谷P1505】 [国家集训队]旅游

    P1505 [国家集训队]旅游 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城 ...

  8. 树链剖分【洛谷P3833】 [SHOI2012]魔法树

    P3833 [SHOI2012]魔法树 题目描述 Harry Potter 新学了一种魔法:可以让改变树上的果子个数.满心欢喜的他找到了一个巨大的果树,来试验他的新法术. 这棵果树共有N个节点,其中节 ...

  9. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  10. 算法复习——树链剖分模板(bzoj1036)

    题目: 题目背景 ZJOI2008 DAY1 T4 题目描述 一棵树上有 n 个节点,编号分别为 1 到 n ,每个节点都有一个权值 w .我们将以下面的形式来要求你对这棵树完成一些操作:I.CHAN ...

随机推荐

  1. Jenkins忘记 admin 密码

    进入 jenkins home(我的是/var/jenkins_home)路径下的users 文件夹 cd /var/jenkins_home/users sudo vim admin/config. ...

  2. ES6-let cont 关键字

    ***let1. 作用: * 与var类似, 用于声明一个变量2. 特点: * 在块作用域内有效 * 不能重复声明 * 不会预处理, 不存在提升3. 应用: * 循环遍历加监听 * 使用let取代va ...

  3. 用Cygwin实现在window环境下使用Linux命令-nohup 来后台运行程序

    1.安装Cygwin 下载 cygdrive-选择64或32位   http://www.cygwin.com/ 注:可以百度搜索安装步骤 2.配置它的环境变量 添加到path路径中 3.cmd  执 ...

  4. 原生js如何获取某一元素的高度

    三种方法: 1.document.getElementById("id").style.height,这种方法的前提是必须之前已经显示的在css中声明过height,才能取得正确的 ...

  5. 用jQuery,ajax,实现三级联动封装JS的文件

    // JavaScript Document $(document).ready(function(e) { //找到ID=SANJI的DIV,造三个下拉扔进去 var str = "< ...

  6. TPCx-BB官宣最新世界纪录,阿里巴巴计算力持续突破

    2019年9月17日,TPC官宣Alibaba Cloud MaxCompute认证结果.同月26日,杭州云栖大会阿里巴巴宣布了这一成绩,飞天大数据平台计算引擎MaxCompute成为全球首个TPCx ...

  7. 高危预警|RDP漏洞或引发大规模蠕虫爆发,用户可用阿里云免费检测服务自检,建议尽快修复

    2019年9月6日,阿里云应急响应中心监测到Metasploit-framework官方在GitHub空间公开了针对Windows远程桌面服务远程命令执行漏洞(CVE-2019-0708)的利用代码. ...

  8. bzoj1096题解

    [解题思路] 预处理spi=∑pj(j∈[1,i]),si=si-1+(xi-xi-1)*spi-1表示把工厂1~i-1的产品都运到工厂i的花费.于是把工厂j+1~i的产品都运到工厂i的花费为si-s ...

  9. python pillow模块用法

    pillow Pillow是PIL的一个派生分支,但如今已经发展成为比PIL本身更具活力的图像处理库.pillow可以说已经取代了PIL,将其封装成python的库(pip即可安装),且支持pytho ...

  10. NX二次开发-UFUN终止UF_terminate

    在调用UFUN函数时必须加Uf.h头文件,代码开头和结尾加UF_initialize和UF_terminate NX9+VS2012 #include <uf.h> #include &l ...