P3833 [SHOI2012]魔法树 (树链剖分模板题)
题目链接:https://www.luogu.org/problem/P3833
题目大意:有一颗含有n个节点的树,初始时每个节点的值为0,有以下两种操作:
1.Add u v d表示将点u和v之间的路径上的所有节点的值都加上d。
2.Query u表示当前果树中,以点u为根的子树中,总共有多少个果子?
解题思路:树链剖分板子,具体看代码注释
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=;
int tot,cnt,head[maxn],n,m,v[maxn];
ll tree[maxn*],lazy[maxn*];
int d[maxn],size[maxn],son[maxn],id[maxn],rk[maxn],fa[maxn],top[maxn];
//size[i]是i的子树的节点数,top[i]是i所在重链的顶端,son[i]是i的重儿子编号
//d[i]是节点i的真深度,id[i]是i的新编号,fa[i]是i的父亲编号
struct Edge{
int v,next;
}edge[maxn<<];
void add(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs1(int u,int pre){ //第一遍dfs求每个节点的深度,父亲节点,所在子树大小
d[u]=d[pre]+;
fa[u]=pre;
size[u]=;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(v!=pre){
dfs1(v,u);
size[u]+=size[v];
if(size[son[u]]<size[v]) son[u]=v;
}
}
}
void dfs2(int u,int tp){ //求每个节点新编号和重儿子和所在重链顶端
top[u]=tp,id[u]=++cnt,rk[cnt]=u;
if(son[u]) dfs2(son[u],tp);
//先跑重儿子节点保证一条重链上各个节点dfs序连续,以便可以通过线段树来维护一条重链的信息
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
void pushup(int rt){
tree[rt]=tree[rt<<]+tree[rt<<|];
}
void pushdown(int l,int r,int rt){
if(lazy[rt]){
tree[rt<<]=tree[rt<<]+lazy[rt]*l;
tree[rt<<|]=tree[rt<<|]+lazy[rt]*r;
lazy[rt<<]+=lazy[rt];
lazy[rt<<|]+=lazy[rt];
lazy[rt]=;
}
}
void build(int l,int r,int rt){
lazy[rt]=;
if(l==r){
tree[rt]=v[rk[l]];
return;
}
int mid=l+r>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
pushup(rt);
}
void update(int L,int R,int val,int l,int r,int rt){
if(L<=l&&R>=r){
tree[rt]+=1ll*(r-l+)*val;
lazy[rt]+=val;
return;
}
int mid=l+r>>;
pushdown(mid-l+,r-mid,rt);
if(mid>=L) update(L,R,val,l,mid,rt<<);
if(mid<R) update(L,R,val,mid+,r,rt<<|);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&R>=r) return tree[rt];
int mid=l+r>>; ll res=;
pushdown(mid-l+,r-mid,rt);
if(mid>=L) res+=query(L,R,l,mid,rt<<);
if(mid<R) res+=query(L,R,mid+,r,rt<<|);
return res;
}
void updates(int x,int y,int val){ //修改x到y最短路径的值
while(top[x]!=top[y]){ //不在同一条重链就向上跳
if(d[top[x]]<d[top[y]]) swap(x,y);
update(id[top[x]],id[x],val,,n,);
x=fa[top[x]]; //跳到该重链顶节点的父节点
}
if(id[x]>id[y]) swap(x,y); //两个节点在同一条重链,但可能不是同一个节点
update(id[x],id[y],val,,n,);
}
ll ask(int x,int y){ //询问x到y最短路径的值
ll res=;
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
res+=query(id[top[x]],id[x],,n,);
x=fa[top[x]];
}
if(id[x]>id[y]) swap(x,y);
res+=query(id[x],id[y],,n,);
return res;
}
int main(){
scanf("%d",&n);
memset(head,-,sizeof(head));
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
u++; v++;
add(u,v);
}
scanf("%d",&m);
cnt=,tot=;
dfs1(,),dfs2(,);
build(,n,);
while(m--){
char op[];
int l,r,rt,val;
scanf("%s",op);
if(op[]=='A'){
scanf("%d%d%d",&l,&r,&val);
l++; r++;
updates(l,r,val);
} else{
scanf("%d",&rt); rt++;
printf("%lld\n",query(id[rt],id[rt]+size[rt]-,,n,));
//因为一个子树的大小是size[rt],起点编号是从id[rt]所以是从id[rt]到id[rt]+size[rt]-1
}
}
return ;
}
P3833 [SHOI2012]魔法树 (树链剖分模板题)的更多相关文章
- BZOJ 2243 染色 | 树链剖分模板题进阶版
BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...
- bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题
[ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...
- BZOJ 1036 树的统计Count 树链剖分模板题
题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1036 题目大意: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将 ...
- 洛谷 P3384 树链剖分(模板题)
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- 【BZOJ 1036】【ZJOI 2008】树的统计 树链剖分模板题
sth神犇的模板: //bzoj1036 题目:一个n个点的树每个点有一个权值,支持修改单点权值,求某两点路径上的点权和或最大点权. #include <cstdio> using nam ...
- 洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- spoj - Grass Planting(树链剖分模板题)
Grass Planting 题意 给出一棵树,树有边权.每次给出节点 (u, v) ,有两种操作:1. 把 u 到 v 路径上所有边的权值加 1.2. 查询 u 到 v 的权值之和. 分析 如果这些 ...
- SPOJ QTREE Query on a Tree【树链剖分模板题】
树链剖分,线段树维护~ #include <cstdio> #include <cstring> #include <iostream> #include < ...
- BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 14982 Solved: 6081[Submit ...
随机推荐
- ES排序值相同顺序随机的问题
ES排序值相同顺序随机的问题 code[class*="language-"] { padding: .1em; border-radius: .3em; white-space: ...
- TiDB官方文档
TiDB官方文档: https://github.com/pingcap/docs-cn TiDB 整体架构 TiDB 集群主要包括三个核心组件:TiDB Server,PD Server 和 TiK ...
- 由ES规范学JavaScript(二):深入理解“连等赋值”问题
var foo={rzx:1} var bar =foo; foo.x=foo={rzx:100} console.log(foo.x) console.log(bar.x) 有这样一个热门问题: ...
- [VBA]获得工作表名称
sub 获得工作表名称() Dim i As Integer For i = 1 To Worksheets.Count Cells(i, 2) = Worksheets(i).Name Next E ...
- 阶段3 1.Mybatis_06.使用Mybatis完成DAO层的开发_6 Mybatis中使用Dao实现类的执行过程分析-增删改方法
从测试类入手,断点调试 找到实现类,进入到insert方法里面 这里是SqlSession的接口里面的方法. 我们需要找SqlSession的实现类. DefaultSqlSession 里面有两个i ...
- 正则表达式——Unicode
第 7 章 Unicode 7.1 关于编码 通常,英文编码较为统一,都采用ASCII编码或可以兼容ASCII编码(即编码表的前127位与ASCII编码一直,常见的各种编码,包括Unicode编码 ...
- c# 匿名委托递归
Func<List<int>, int> GetVirtualCode = null; // 递归不能直接=,要赋初值.微软得优化啊,这语法糖不够甜 GetVirtualCod ...
- [LeetCode] 1092. Shortest Common Supersequence
LeetCode刷题记录 传送门 Description Given two strings str1 and str2, return the shortest string that has bo ...
- python 开启进程两种方法 multiprocessing模块 介绍
一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu\_count\(\)查看),在python中大部分情况需要使用多进 ...
- SQLSERVER 备份恢复之后提示缺少创建表权限的问题解决
1. 同事这边出现异常: 执行功能是报错, 这个错误 应该是创建临时表时没有权限触发的. 方法应该很简单 缺少权限增加权限即可 2. 这里需要使用sa 或者是 具有sa权限的用户登录 打开 数据库级别 ...