树链剖分模板(洛谷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 ...
随机推荐
- 我们如何用Go来处理每分钟100万复杂请求的场景
在Malwarebytes我们经历了显著的增长,自从我一年前加入了硅谷的公司,一个主要的职责成了设计架构和开发一些系统来支持一个快速增长的信息安全公司和所有需要的设施来支持一个每天百万用户使用的产品. ...
- 收集JavaScript中常用的方法函数
本文中,收集了一些比较常用的Javascript函数,希望对学习JS的朋友们有所帮助. 1. 字符串长度截取 function cutstr(str, len) { var temp, icount ...
- 记一次 HTTP信息头管理器使用 的重要性
今天在测试中遇到了一个问题 使用JMeter时请求相关地址参数及方法都填写正确,但是相应数据返回始终不对,例如 查看取样器结果显示 200 正常,但响应数据不符合正常的结果. 经反复检查发现问题如下: ...
- Java programming problems
1.使用循环把26个字母按字典顺序存入数组,在不使用另外数组的情况下将其逆序存放,在根据处理后的字符数组创建一个字符串并输出 public static void main(String[] args ...
- haploview画出所有SNP的LD关系图
有时候我们想画出所有SNP的LD关系图,则需要在命令行添加“-skipcheck”命令行,如下所示: java -jar Haploview.jar -skipcheck -n -pedfile 80 ...
- JavaBean+Servlet 开发时,JavaBean 编写问题
在开发 JavaBean 时,遇见一个问题: ***** 表单字段为空,提交时出现 nullPointerException 异常: 表单字段不为空,提交正常. 使用 JavaBean ,JSP页 ...
- 数据库MySQL
--IN 关键字 在.....里 SELECT * FROM zhangwu WHERE money IN (66,666,700); 1.主键约束 特点非空 只用于表示當前的记录 primary k ...
- MySQL会发生死锁吗?
SHOW ENGINE INNODB STATUS;来查看死锁日志: SHOW PROCESSLIST;查看进程 MySQL的InnoDB引擎事务有4种隔离级别,主要是为了保证数据的一致性. Inno ...
- DBMS客户端是否安装:Make sure DBMS client is installed and this required library is available for dynamic loading
Symptom The full error message is as follows:Error logging in. Unable to process the database trans ...
- C# 实现身份验证之WCF篇(1)
WCF身份验证一般常见的方式有:自定义用户名及密码验证.X509证书验证.ASP.NET成员资格(membership)验证.SOAP Header验证.Windows集成验证.WCF身份验证服务(A ...