洛谷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)的更多相关文章

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

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

  2. 树链剖分( 洛谷P3384 )

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. 洛谷P1041 传染病控制

    解:搜索...... 我们可以每次选择分支少的搜索,或者说,贪心的搜索当前更优的决策. 每一层把能剪的点搞出来,按照度数/SIZ排序,然后依次搜索.加个最优化剪枝就完事了. #include < ...

  2. IO 流读取文件时候出现乱码 文件编码格式问题 怎么转换解决方法

    在使用下面这个写法时候UTF-8文件编码 在读取时候出现乱码问题. File myFile=new File("文件路径"); BufferedReader in = new Bu ...

  3. Win32 SDK:ListBox 为什么不整个 LB_SETTEXT

    Win32 & SDK: ListBox 有个 LB_GETTEXT,为什么没有 LB_SETTEXT,想修改指定Item的Text,还真不容易. 自已写了一个,支持单选和多选模式,部分代码: ...

  4. ubuntu vim01

    不小心按了ctrl+s(停止向终端输入),解决办法ctrl+q(恢复向终端输入)

  5. linux服务器上tomcat日志中的中文乱码

    转: 修改tomcat应用日志默认编码格式 前言 今天开发跟我说tomcat日志中的中文不能正常显示,根据以往的经验,我觉得可能跟服务器的编码有关,于是尝试各种方法,但还是没能解决问题. 后来我突然想 ...

  6. maven+testng+eclipse

    1.安装maven 2.安装testng 3.配置maven的dependency,和build <project xmlns="http://maven.apache.org/POM ...

  7. Luogu P3966 [TJOI2013]单词

    题目链接 \(Click\) \(Here\) 本题\(AC\)自动机写法的正解之一是\(Fail\)树上跑\(DP\). \(AC\)自动机是\(Trie\)树和\(Fail\)树共存的结构,前者可 ...

  8. mysql中using

    select * from ( SELECT u.utm_source ,count(DISTINCT u.mobile) as new_user -- 登记用户 FROM 表名 u WHERE u. ...

  9. 将二维list某列组成新的list

    # encoding: utf-8 import decimal import requests import logging import logging.config import random ...

  10. Zabbix Server 自带模板监控更加灵活MySQL数据库

    Zabbix Server 自带模板监控更加灵活MySQL数据库 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.  一.zabbix-agent端配置 1>.修改zabbix的 ...