题目链接: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]魔法树 (树链剖分模板题)的更多相关文章

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

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

  2. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

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

  3. BZOJ 1036 树的统计Count 树链剖分模板题

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1036 题目大意: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将 ...

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

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

  5. 【BZOJ 1036】【ZJOI 2008】树的统计 树链剖分模板题

    sth神犇的模板: //bzoj1036 题目:一个n个点的树每个点有一个权值,支持修改单点权值,求某两点路径上的点权和或最大点权. #include <cstdio> using nam ...

  6. 洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)

    题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...

  7. spoj - Grass Planting(树链剖分模板题)

    Grass Planting 题意 给出一棵树,树有边权.每次给出节点 (u, v) ,有两种操作:1. 把 u 到 v 路径上所有边的权值加 1.2. 查询 u 到 v 的权值之和. 分析 如果这些 ...

  8. SPOJ QTREE Query on a Tree【树链剖分模板题】

    树链剖分,线段树维护~ #include <cstdio> #include <cstring> #include <iostream> #include < ...

  9. BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14982  Solved: 6081[Submit ...

随机推荐

  1. vue 中 event.stopPropagation() 和event.preventDefault() 使用

    1.event.stopPropagation()方法 这是阻止事件的冒泡方法,不让事件向document上蔓延,但是默认事件任然会执行,当你掉用这个方法的时候,如果点击一个连接,这个连接仍然会被打开 ...

  2. KVM 记录

    mkdir -p /home/hugepagesmount -t hugetlbfs hugetlbfs /home/hugepages 配置文件 vim /etc/libvirt/qemu.conf ...

  3. SPRING AOC、AOP 概念详解

    AOC 依赖注入:就是通过容器来控制业务对象之间的依赖关系.也就是把需要的业务对象都放入容器中,需要注入时,通过反射技术来动态获取指定的对象,装配到当前使用对象.代替了原始的 new 来实现对象的实例 ...

  4. 十二、RF自定义库(数据库)

    1.自定义第三方库 def DB_select_by_sql(self,db_name,sql): conn=pymysql.connect(db=db_name,user='root',passwo ...

  5. 使用ffmpeg来转换media Video

    FFMPEG -i 1.wmv -c:v libx264 -strict -2 1_wmv.mp4 ffmpeg -i b.mp4 -codec copy -bsf h264_mp4toannexb ...

  6. 码云 git 命令提交

    E:\project\eddy-boot-focus>git init E:\project\eddy-boot-focus>git remote add origin https://g ...

  7. pycharm运行测试用例遇到错误:ZeroDivisionError: float division by zero的原因

    运行测试用例报错:ZeroDivisionError: float division by zero 一般是因为测试用例模块命名没有以test开头,导致unittest找不到用例,用例总数为0,导致除 ...

  8. java保留2位或n位小数

    1.直接使用字符串处理 double ds = Double.valueOf(String.format("%.3f", Math.random()).toString()); 这 ...

  9. (一)VS2015下配置OpenGL

    刚开始用OpenGL,一开始不太明白配置库的原理,在VS2015下耗费了大量时间.这里将配置过程做个笔记,以供日后查看.配置过程中,需要下载cmake构建工具以及glew和glfw库. 下载地址为: ...

  10. 精读《What's new in javascript》

    1. 引言 本周精读的内容是:Google I/O 19. 2019 年 Google I/O 介绍了一些激动人心的 JS 新特性,这些特性有些已经被主流浏览器实现,并支持 polyfill,有些还在 ...