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 ...
随机推荐
- How to Create a Basic Plugin 如何写一个基础的jQuery插件
How to Create a Basic Plugin Sometimes you want to make a piece of functionality available throughou ...
- C++获取寄存器eip的值
程序中需要打印当前代码段位置 如下 #include <stdio.h> #include <stdlib.h> #include <math.h> #ifdef ...
- ffmpeg保持原视频画面比例 自动添加黑边
ffmpeg保持原视频画面比例 自动添加黑边 例如源是1280*528要转成640*480要保持画面比例实际上应该640*264 所以需要在上下都加黑边 ffmpeg -i d:/Media/e.f4 ...
- leetcode-mid-dynamic programming-55. Jump Game
mycode 71.47% 思路: 既然要到达终点,那么俺就可以倒推,要想到达n,可以有以下情况 1)到达n-1,然后该位置最少可以走一步 2)到达n-2,然后该位置最少可以走两步 3)到达n-3, ...
- Flask 中的蓝图
相当与django中的App 基础模板 1.初识Flask蓝图(blueprint) 创建一个项目然后将目录结构做成: s_view.py 文件中的内容 from flask import Blu ...
- C++ 左值与右值
https://baike.baidu.com/item/%E5%B7%A6%E5%80%BC%E4%B8%8E%E5%8F%B3%E5%80%BC/5537417?fr=aladdin https: ...
- Quartz安装包中的15个example
Welcome======= Welcome to the Quartz Examples directory. This directory contains 15 examples that sh ...
- lua源码学习篇三:赋值表达式解析的流程
上节说到表达式的解析问题,exprstate函数用于解析普通的赋值表达式.lua语言支持多变量赋值.本文先从单变量赋值表达式讲起. a = b = c = a + b 对于简单的两个数的求和过程,lu ...
- C# 获取当前网页HTML
//引用COM组件 //Microsoft HTML Object Library //Microsoft Internet Controls SHDocVw.ShellWindows shellWi ...
- centos7:Kafka集群安装
解压文件到安装目录 tar -zxvf kafka_2.10-0.10.2.1.tgz 1.进入目录 cd kafka_2.10-0.10.2.1 mkdir logs cd config cp se ...