树链剖分模板(洛谷P3384)
#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl;
const int maxn = 1e5+5;
using namespace std; inline int read(){
int x=0,f=1;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 n,m,rot,mod;
int w[maxn],wt[maxn];///剖分前后的点权,不要抄错QAQ
int head[maxn],tot;
int cnt,dep[maxn],siz[maxn],fa[maxn],son[maxn],id[maxn],top[maxn];///son[i]表示i的重儿子,top[i]表示i所在链的顶点
int ans; struct treenode{
int l,r,val,add;
}tree[maxn<<2]; struct edgenode{
int to,next;
}edge[maxn<<1]; void addedge(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
} void push_up(int x){
tree[x].val=tree[x<<1].val+tree[x<<1|1].val;
tree[x].val%=mod;
} void push_down(int x,int len){
if(tree[x].add){
tree[x<<1].add+=tree[x].add;
tree[x<<1|1].add+=tree[x].add;
tree[x<<1].val+=(len-(len>>1))*tree[x].add;
tree[x<<1|1].val+=(len>>1)*tree[x].add;
tree[x<<1].val%=mod;
tree[x<<1|1].val%=mod;
tree[x].add=0;
}
} void build(int i,int l,int r){
tree[i].l=l;
tree[i].r=r;
tree[i].add=0;
if(l == r){
tree[i].val=wt[l];
tree[i].val%=mod;
return;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
push_up(i);
} void update(int i,int l,int r,int L,int R,int c){
if(l >= L && r <= R){
tree[i].val+=(r-l+1)*c;
tree[i].add+=c;
return;
}
push_down(i,r-l+1);
int mid=(l+r)>>1;
if(L <= mid)update(i<<1,l,mid,L,R,c);
if(R > mid)update(i<<1|1,mid+1,r,L,R,c);
push_up(i);
} void query(int i,int l,int r,int L,int R){
if(l >= L && r <= R){
ans+=tree[i].val;
ans%=mod;
return;
}
push_down(i,r-l+1);
int mid=(l+r)>>1;
if(L <= mid)query(i<<1,l,mid,L,R);
if(R > mid)query(i<<1|1,mid+1,r,L,R);
} void dfs1(int x,int pre,int deep){///确定各节点层次,子树大小,父节点编号,重儿子编号
dep[x]=deep;
fa[x]=pre;
siz[x]=1;
int maxson=-1;
for(int i=head[x];i != -1;i=edge[i].next){
int v=edge[i].to;
if(v != pre){
dfs1(v,x,deep+1);
siz[x]+=siz[v];
if(siz[v] > maxson){maxson=siz[v];son[x]=v;}
}
}
} void dfs2(int x,int topf){///确定各链的信息,包括链的顶点以及链上点的新编号
id[x]=++cnt;
wt[id[x]]=w[x];
top[x]=topf;
if(!son[x])return;
dfs2(son[x],topf);
for(int i=head[x];i != -1;i=edge[i].next){
int v=edge[i].to;
if(v == fa[x] || v == son[x])continue;
dfs2(v,v);
}
} void spilt(){
dfs1(rot,0,1);
dfs2(rot,rot);
build(1,1,n);
}
/*查询两点路径上的点权和*/
int qRange(int x,int y){///让深度深的点往上跳到顶点并更新对答案的贡献
int res=0; ///之后更新到旧链顶上的链,重复过程直到两点在同一条链上
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]])swap(x,y);
ans=0;
query(1,1,n,id[top[x]],id[x]);
res+=ans;
res%=mod;
x=fa[top[x]];
}
if(dep[x] > dep[y])swap(x,y);
ans=0;
query(1,1,n,id[x],id[y]);
res+=ans;
return res%mod;
}
/*更新同查询*/
void updRange(int x,int y,int c){
c%=mod;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x],c);
x=fa[top[x]];
}
if(dep[x] > dep[y])swap(x,y);
update(1,1,n,id[x],id[y],c);
}
/*查询子树点权和*/
int qSon(int x){///由于新编号连续,直接查询树根到树根+树的大小,这段区间对应整个子树
ans=0;
query(1,1,n,id[x],id[x]+siz[x]-1);
return ans;
}
/*更新同查询*/
void updSon(int x,int c){
update(1,1,n,id[x],id[x]+siz[x]-1,c);
} int main(){
memset(head,-1,sizeof head);
n=read(),m=read(),rot=read(),mod=read();
for(int i=1;i<=n;i++)w[i]=read();
for(int i=1;i<=n-1;i++){
int a=read(),b=read();
addedge(a,b);
addedge(b,a);
}
spilt();///剖分
for(int i=1;i<=m;i++){
int op,x,y,z;
op=read();
if(op == 1){
x=read(),y=read(),z=read();
updRange(x,y,z);
}
if(op == 2){
x=read(),y=read();
printf("%d\n",qRange(x,y));
}
if(op == 3){
x=read(),y=read();
updSon(x,y);
}
if(op == 4){
x=read();
printf("%d\n",qSon(x));
}
}
return 0;
}
树链剖分模板(洛谷P3384)的更多相关文章
- 【树链剖分】洛谷P3384树剖模板
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- 树链剖分( 洛谷P3384 )
我们有时候遇到这样一类题目,让我们维护树上路径的某些信息,这个时候发现我们无法用线段树或者树状数组来维护这些信息,那么我们就有着一种新的数据结构,树剖:将一棵树划分成若干条链,用数据结构去维护每条链, ...
- 【树链剖分】洛谷P3379 树链剖分求LCA
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 树链剖分【洛谷P4114】 Qtree1
P4114 Qtree1 题目描述 给定一棵n个节点的树,有两个操作: CHANGE i ti 把第i条边的边权变成ti QUERY a b 输出从a到b的路径中最大的边权,当a=b的时候,输出0 码 ...
- 树链剖分【洛谷P2590】 [ZJOI2008]树的统计
P2590 [ZJOI2008]树的统计 题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把 ...
- 树链剖分【洛谷P1505】 [国家集训队]旅游
P1505 [国家集训队]旅游 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城 ...
- 树链剖分【洛谷P3833】 [SHOI2012]魔法树
P3833 [SHOI2012]魔法树 题目描述 Harry Potter 新学了一种魔法:可以让改变树上的果子个数.满心欢喜的他找到了一个巨大的果树,来试验他的新法术. 这棵果树共有N个节点,其中节 ...
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
- 算法复习——树链剖分模板(bzoj1036)
题目: 题目背景 ZJOI2008 DAY1 T4 题目描述 一棵树上有 n 个节点,编号分别为 1 到 n ,每个节点都有一个权值 w .我们将以下面的形式来要求你对这棵树完成一些操作:I.CHAN ...
随机推荐
- C# Winform 对话框控件&简单记事本
一.对话框 1.弹出可供用户选择“确定”.“取消”的对话框 Dialogresult dr = MessigeBox.Show("这里显示的是对话框的内容","这里显示 ...
- poj2259 Team Queue
吼哇,又是水题. 我本来准备开1010个queue的,但是STL容器里好像只有vector滋磁开组,于是只好数组模拟... 然后模拟过了...... #include <cstdio> # ...
- Remote debugger is in a background tab which may cause apps to perform slowly. Fix this by foregrounding the tab (or opening it in a separate window).
先上代码: /** * Sample React Native App * https://github.com/facebook/react-native * * @format * @flow * ...
- PHP快速排序算法
说明: 通过设置一个初始中间值,来将需要排序的数组分成3部分,小于中间值的左边,中间值,大于中间值的右边,继续递归用相同的方式来排序左边和右边,最后合并数组 示例: <?php $a = arr ...
- echarts map地图设置外边框或者阴影
geo: { map: 'china', center: [112.194115019531, 23.582111640625], zoom: 12, aspectScale: 1, //长宽比 la ...
- Circular view path xxx would dispatch back to the current handler URL,Check your ViewResolver setup
Circular view path xxx would dispatch back to the current handler URL 通过原因分析,造成问题有两个因素:1). 缺省转发, 2). ...
- halcon几何变换(仿射变换)
旋转.平移.镜像.缩放.斜切,可参考https://blog.csdn.net/machaoyu86/article/details/51182473 仿射变换前,需要获得仿射变换矩阵. 关于shap ...
- windows怎样查看被程序占用的端口
1. netstat -ano 显示所有端口与任务管理器中的pid对应,通过pid打开任务管理器查询占用进程 附录:在命令行中输入netstat /? 可以查看netstat的相关信息.C:\Doc ...
- node.js(小案例)_实现学生信息增删改
一.前言 本节内容主要对小案例做一个总结: 1.如何开始搭建小项目 2.路由设计 3.模块应用 4.项目源码以及实现过程github地址: 项目演示如下: 二.主要内容 1.项目的关键性js源码: 项 ...
- PHP下安装memcached
tar xvf libevent-2.0.21-stable.tar.gzcd libevent./configure -prefix=/usr/local/libeventmake &&am ...