树链剖分【洛谷P3833】 [SHOI2012]魔法树
P3833 [SHOI2012]魔法树
题目描述
Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。
这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。
不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:
Add u v d
表示将点u和v之间的路径上的所有节点的果子个数都加上d。
接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:
Query u
表示当前果树中,以点u为根的子树中,总共有多少个果子?
输入输出格式
输入格式:
第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。
接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。
接下来是一个正整数Q(1 ≤ Q ≤ 100000),表示共有Q次操作。
后面跟着Q行,每行是以下两种中的一种:
- A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000
- Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。
输出格式:
对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。
省选考树剖裸题。。。
code:
#include <iostream>
#include <cstdio>
#define ls(o) o<<1
#define rs(o) o<<1|1
#define int long long
using namespace std;
const int wx=100017;
inline int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
return sum*f;
}
int dfn[wx],tid[wx];
int dep[wx],f[wx],size[wx],son[wx];
int top[wx];
int head[wx],a[wx];
int n,m,num,tot;
char opt[17];
struct val_tree{
int l,r,tag,sum;
#define tag(o) t[o].tag
#define sum(o) t[o].sum
}t[wx*4];
void up(int o){
sum(o)=sum(ls(o))+sum(rs(o));
}
void down(int o){
if(tag(o)){
sum(ls(o))+=tag(o)*(t[ls(o)].r-t[ls(o)].l+1);
sum(rs(o))+=tag(o)*(t[rs(o)].r-t[rs(o)].l+1);
tag(ls(o))+=tag(o); tag(rs(o))+=tag(o);
tag(o)=0;
}
}
void build(int o,int l,int r){
t[o].l=l;t[o].r=r;
if(l==r){sum(o)=a[tid[l]];return ;}
int mid=t[o].l+t[o].r>>1;
if(l<=mid)build(ls(o),l,mid);
if(r>mid)build(rs(o),mid+1,r);
up(o);
}
void update_t(int o,int l,int r,int k){
if(l<=t[o].l&&t[o].r<=r){
sum(o)+=k*(t[o].r-t[o].l+1);
tag(o)+=k; return ;
}
down(o);
int mid=t[o].l+t[o].r>>1;
if(l<=mid)update_t(ls(o),l,r,k);
if(r>mid)update_t(rs(o),l,r,k);
up(o);
}
int query_t(int o,int l,int r){
if(l<=t[o].l&&t[o].r<=r){
return sum(o);
}
down(o); int sum=0;
int mid=t[o].l+t[o].r>>1;
if(l<=mid)sum+=query_t(ls(o),l,r);
if(r>mid)sum+=query_t(rs(o),l,r);
return sum;
}
//~~~~~~~~~~~~~~~~~~~~~~~~
struct e{
int nxt,to;
}edge[wx*2];
void add(int from,int to){
edge[++num].nxt=head[from];
edge[num].to=to;
head[from]=num;
}
void first_dfs(int u,int fa){
f[u]=fa;dep[u]=dep[fa]+1;
size[u]=1;
int maxson=-1;
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(v==fa)continue;
first_dfs(v,u);
size[u]+=size[v];
if(size[v]>maxson){
son[u]=v; maxson=size[v];
}
}
}
void second_dfs(int u,int topf){
dfn[u]=++tot;
top[u]=topf;
tid[tot]=u;
if(son[u]){
second_dfs(son[u],topf);
}
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(dfn[v]||v==son[u])continue;
second_dfs(v,v);
}
}
void update(int x,int y,int k){
int fx=top[x]; int fy=top[y];
while(fx!=fy){
if(dep[fx]>dep[fy]){
update_t(1,dfn[fx],dfn[x],k);
x=f[fx];
}
else{
update_t(1,dfn[fy],dfn[y],k);
y=f[fy];
}
fx=top[x]; fy=top[y];
}
if(dfn[x]>dfn[y]) swap(x,y);
update_t(1,dfn[x],dfn[y],k);
return ;
}
signed main(){
n=read();
for(int i=1;i<n;i++){
int x,y;
x=read(); y=read();
x++; y++;
add(x,y);add(y,x);
}
first_dfs(1,0);
second_dfs(1,1);
build(1,1,n);
m=read();
for(int i=1;i<=m;i++){
scanf("%s",opt+1);
if(opt[1]=='A'){
int x,y,z;
x=read();y=read();z=read();
x++; y++;
update(x,y,z);
}
else{
int x; x=read(); x++;
printf("%lld\n",query_t(1,dfn[x],dfn[x]+size[x]-1));
}
}
return 0;
}
树链剖分【洛谷P3833】 [SHOI2012]魔法树的更多相关文章
- 洛谷——P3833 [SHOI2012]魔法树
P3833 [SHOI2012]魔法树 题目背景 SHOI2012 D2T3 题目描述 Harry Potter 新学了一种魔法:可以让改变树上的果子个数.满心欢喜的他找到了一个巨大的果树,来试验他的 ...
- 洛谷 P3833 [SHOI2012]魔法树
题目背景 SHOI2012 D2T3 题目描述 Harry Potter 新学了一种魔法:可以让改变树上的果子个数.满心欢喜的他找到了一个巨大的果树,来试验他的新法术. 这棵果树共有N个节点,其中节点 ...
- [洛谷P3833][SHOI2012]魔法树
题目大意:给一棵树,路径加,子树求和 题解:树剖 卡点:无 C++ Code: #include <cstdio> #include <iostream> #define ma ...
- 洛谷3833 [SHOI2012]魔法树
SHOI2012 D2T3 题目描述 Harry Potter 新学了一种魔法:可以让改变树上的果子个数.满心欢喜的他找到了一个巨大的果树,来试验他的新法术. 这棵果树共有N个节点,其中节点0是根节点 ...
- AC日记——【模板】树链剖分 洛谷 P3384
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- 洛谷P3833 [SHOI2012]魔法树(树链剖分)
传送门 树剖板子…… 一个路径加和,线段树上打标记.一个子树询问,dfs的时候记录一下子树的区间就行 // luogu-judger-enable-o2 //minamoto #include< ...
- P3833 [SHOI2012]魔法树
思路 树剖板子 注意给出点的编号是从零开始的 代码 #include <cstdio> #include <algorithm> #include <cstring> ...
- 洛谷 P3384 【模板】树链剖分
树链剖分 将一棵树的每个节点到它所有子节点中子树和(所包含的点的个数)最大的那个子节点的这条边标记为"重边". 将其他的边标记为"轻边". 若果一个非根节点的子 ...
- 树链剖分详解(洛谷模板 P3384)
洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 emm还有必备的 链式前向星.线段树 也要先学了. 如果这三个知识点没掌握好的话,树链剖 ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
随机推荐
- maven学习6 Eclipse下Tomcat常用设置
Eclipse下Tomcat常用设置 1,Eclipse建立Tomcat服务 1.1 新建Server 首先这里是指,jee版的Eclipse.Eclipse是没有像MyEclipse那样集成Tomc ...
- docker 端口映射iptables: No chain/target/match by that name错误解决方法
pkill docker iptables -t nat -F ifconfig docker0 down brctl delbr docker0 service docker restart
- Codeforces Round #310 (Div. 2)556ABCDE
https://github.com/Anoxxx/OI/blob/master/Anoxx/Contest10 github自取
- 10-09C#语言基础
10-09C#语言基础 第一课 一.新项目的建立:打开Visual studio2012,单击“文件→新建项目→模板isualC# Windows 控制台应用程序→确定”即可. 在新建的项目中,首 ...
- Android getWidth和getMeasuredWidth的区别
getWidth 得到的事某个View的实际尺寸. getMeasuredWidth 得到的是某个View想要在parent view里面占的大小 相比你也见过这样的解释,听起来这样的解释也是云里雾里 ...
- 无人驾驶——4.控制之MPC模型预测控制
源自:<无人驾驶无人驾驶车辆模型预测控制>——龚建伟 参考:https://wenku.baidu.com/view/8e4633d519e8b8f67c1cb9fa.html 0.车辆模 ...
- explode()与相反函数 implode() 和join()
explode()的函数原型: array explode(string separator,string input [,int limit]); //[,int limit]是表示可选的意思 参数 ...
- PHP的count(数组)和strlen(字符串)的内部实现
PHP的count(数组)和strlen(字符串)的内部实现上是直接显示一个长度变量,还是重头依次数一遍有多少个元素?关乎我理解这2个函数的效率..希望高人能从php的c源码上讲一讲.没有源码看过源码 ...
- TortoiseSVN客户端安装遇到的问题汇总
在windows server 2003版本上安装32位SVN客户,提示以下错误 1:无法通过windows installer服务安装此安装程序包” 这时需要安装更新的windows install ...
- ubuntu16.04 安装opencv3.4
1.去官网下载opencv,在本教程中选用的时opencv3.4.1,其他版本的配置方法异曲同工. 下载链接http://opencv.org/releases.html,选择sources版本 2. ...