树剖||树链剖分||线段树||BZOJ4034||Luogu3178||[HAOI2015]树上操作
好像其他人都嫌这道题太容易了懒得讲,好吧那我讲。
题解:第一个操作和第二个操作本质上是一样的,所以可以合并。唯一值得讲的点就是:第二个操作要求把某个节点 x 为根的子树中所有点的点权都增加 a,我们可以发现一个子树中的结点在线段树中会是连续的一段,而这段数最后一个就是seg值(seg数组在Dfs2中有进行预处理,seg[x]:x结点在线段树中的位置)最大的那个。所以可以在Dfs2中多预处理一个tu[x]表示以x为根的子树中seg值最大的结点的seg值。接下来进行操作二时Update(1,seg[x],tu[x])就可以了。总体挺模版的,而且由于询问只询问x到根的和,所以不需要预处理dep数组。记得开ll。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
inline ll rd(){
ll x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-; c=getchar();}
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return f*x;
}
const ll maxn=,maxq=;
ll N,Q,num_edge=,edge_head[maxn],W[maxn],a,b,seg[maxn],rev[maxn],fa[maxn];
ll top[maxn],son[maxn],size[maxn],tu[maxn],X,A,Ans,o;
struct Edge{
int to,nx;
}edge[maxn<<];
inline void Add_edge(int from,int to){
edge[++num_edge].nx=edge_head[from];
edge[num_edge].to=to;
edge_head[from]=num_edge;
return;
}
inline void Dfs1(int x,int f){
fa[x]=f;
size[x]=;
for(int i=edge_head[x];i;i=edge[i].nx){
int y=edge[i].to;
if(y!=f){
Dfs1(y,x);
size[x]+=size[y];
if(size[y]>size[son[x]])son[x]=y;
}
}
return;
}
inline void Dfs2(int x){
tu[x]=seg[];
if(son[x]){
int y=son[x];
seg[y]=++seg[];//seg[x]:x在线段树中的下标
rev[seg[]]=y;
top[y]=top[x];
Dfs2(y);
tu[x]=max(tu[x],tu[y]);
}
for(int i=edge_head[x];i;i=edge[i].nx){
int y=edge[i].to;
if(top[y]==){
seg[y]=++seg[];
rev[seg[]]=y;
top[y]=y;
Dfs2(y);
tu[x]=max(tu[x],tu[y]);
}
}
return;
}
struct Tree{
ll sum,l,r,flag;
}t[maxn<<];
inline void Build(int k,int l,int r){
t[k].l=l;t[k].r=r;
if(l==r){
t[k].sum=W[rev[l]];
return;
}
int mid=(l+r)>>,ls=k<<,rs=k<<|;
Build(ls,l,mid);Build(rs,mid+,r);
t[k].sum=t[ls].sum+t[rs].sum;
return;
}
inline void Pushdown(int k){
if(t[k].flag){
int ls=k<<,rs=k<<|,ln=t[ls].r-t[ls].l+,rn=t[rs].r-t[rs].l+;
t[ls].sum+=t[k].flag*ln;t[rs].sum+=t[k].flag*rn;
t[ls].flag+=t[k].flag;t[rs].flag+=t[k].flag;
t[k].flag=;
}
return;
}
inline void Update(int k,int ql,int qr,ll s){
int l=t[k].l,r=t[k].r;
if(ql<=l&&r<=qr){
t[k].sum+=s*(r-l+);
t[k].flag+=s;
return;
}
Pushdown(k);
int mid=(l+r)>>,ls=k<<,rs=k<<|;
if(ql<=mid)Update(ls,ql,qr,s);
if(qr>mid)Update(rs,ql,qr,s);
t[k].sum=t[ls].sum+t[rs].sum;
return;
}
inline void Query(int k,int ql,int qr){
int l=t[k].l,r=t[k].r;
if(ql<=l&&r<=qr){
Ans+=t[k].sum;
return;
}
Pushdown(k);
int mid=(l+r)>>,ls=k<<,rs=k<<|;
if(ql<=mid)Query(ls,ql,qr);
if(qr>mid)Query(rs,ql,qr);
return;
}
inline ll Ask(int x){
int fx=top[x];
Ans=;
while(fx!=){
Query(,seg[fx],seg[x]);
x=fa[fx];
fx=top[x];
}
Query(,,seg[x]);
return Ans;
}
int main(){
N=rd();Q=rd();
for(int i=;i<=N;i++)W[i]=rd();
for(int i=;i<N;i++){
a=rd();b=rd();
Add_edge(a,b);
Add_edge(b,a);
}
Dfs1(,);
seg[]=seg[]=rev[]=top[]=;
Dfs2();
Build(,,N);
while(Q--){
o=rd();
if(o==||o==){
X=rd();A=rd();
if(o==)Update(,seg[X],seg[X],A);
else Update(,seg[X],tu[X],A);
}
else{
X=rd();
printf("%lld\n",Ask(X));
}
}
return ;
}
By:AlenaNuna
树剖||树链剖分||线段树||BZOJ4034||Luogu3178||[HAOI2015]树上操作的更多相关文章
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
- 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树
[BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树
正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...
- 【bzoj2402】陶陶的难题II 分数规划+树链剖分+线段树+STL-vector+凸包+二分
题目描述 输入 第一行包含一个正整数N,表示树中结点的个数.第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5).第三行包含N个正实数,第i个数表示yi (1<=yi& ...
- 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并
题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...
- [HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]
题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个 ...
- 【bzoj1036】树的统计[ZJOI2008]树链剖分+线段树
题目传送门:1036: [ZJOI2008]树的统计Count 这道题是我第一次打树剖的板子,虽然代码有点长,但是“打起来很爽”,而且整道题只花了不到1.5h+,还是一遍过样例!一次提交AC!(难道前 ...
随机推荐
- 使用 cmake 进行交叉编译
cmake 因为“又”要额外学一门语言而被诟病,但这并不妨碍越来越多私人项目用 cmake 来管理:autoconfig 确实是更好的发行工具,但用 cmake 管理项目显然更加的容易.如果要应用这些 ...
- void android.graphics.Bitmap.recycle()
void android.graphics.Bitmap.recycle() Free up the memory associated with this bitmap's pixels, and ...
- 【RS】Sparse Probabilistic Matrix Factorization by Laplace Distribution for Collaborative Filtering - 基于拉普拉斯分布的稀疏概率矩阵分解协同过滤
[论文标题]Sparse Probabilistic Matrix Factorization by Laplace Distribution for Collaborative Filtering ...
- wkhtmlpdf安装以及中文乱码
见此页http://www.cnblogs.com/day959/p/6652726.html
- android的activity被杀死后如何重启
最近公司的大屏展示机器人上的程序运行时间长了,比如五天,十天会出现偶尔的崩溃,查日志可能是内存溢出或者是ndk层的错误,这种错误一时也不太好查找,但是产品那边有个要求就是程序退出了一定要能重启,能抓日 ...
- 将iPhone5s中的相片批量下载到电脑中
前言:目前我还在使用iPhone5s这款手机,不过由于自己的无知,在使用手机的过程中发现有些用户的体验不是很好,特别是将手机中的相片批量下载到电脑中这件小事,和Android系统相关的手机相比更不好玩 ...
- C#:CeF遇到的问题
2.CSharp与JS交互问题: 1)在 继承CefRenderProcessHandler的子类中重载OnWebKitInitialized()函数,注册JS类 2)在 继承CefApp的子类中创建 ...
- IOS开发 文件路径
1.开发平台路径: /Developer/Platforms 此路径下一般有三个目录,分别是mac电脑.模拟器.iphone真机 MacOSX.platform iPhoneSimulator.pla ...
- [k8s]k8s-ceph-statefulsets-storageclass-nfs 有状态应用布署实践
k8s stateful sets storageclass 有状态应用布署实践v2 Copyright 2017-05-22 xiaogang(172826370@qq.com) 参考 由于网上的文 ...
- 一篇文章掌握RequireJS常用知识
本文采取循序渐进的方式,从理论到实践,从RequireJS官方API文档中,总结出在使用RequireJS过程中最常用的一些用法,并对文档中不够清晰具体的内容,加以例证和分析,分享给大家供大家参考,具 ...