题面:P3178 [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]树上操作的更多相关文章

  1. bzoj4034 (树链剖分+线段树)

    Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...

  2. 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树

    [BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...

  3. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  4. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  5. 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树

    正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...

  6. 【bzoj2402】陶陶的难题II 分数规划+树链剖分+线段树+STL-vector+凸包+二分

    题目描述 输入 第一行包含一个正整数N,表示树中结点的个数.第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5).第三行包含N个正实数,第i个数表示yi (1<=yi& ...

  7. 【bzoj2325】[ZJOI2011]道馆之战 树链剖分+线段树区间合并

    题目描述 给定一棵树,每个节点有上下两个格子,每个格子的状态为能走或不能走.m次操作,每次修改一个节点的状态,或询问:把一条路径上的所有格子拼起来形成一个宽度为2的长方形,从起点端两个格子的任意一个开 ...

  8. [HDU3710] Battle Over Cities [树链剖分+线段树+并查集+kruskal+思维]

    题面 一句话题意: 给定一张 N 个点, M 条边的无向连通图, 每条边上有边权 w . 求删去任意一个点后的最小生成树的边权之和. 思路 首先肯定要$kruskal$一下 考虑$MST$里面去掉一个 ...

  9. 【bzoj1036】树的统计[ZJOI2008]树链剖分+线段树

    题目传送门:1036: [ZJOI2008]树的统计Count 这道题是我第一次打树剖的板子,虽然代码有点长,但是“打起来很爽”,而且整道题只花了不到1.5h+,还是一遍过样例!一次提交AC!(难道前 ...

随机推荐

  1. 一个可以参考的JVM内存分配

    下面是java命令有关JVM内存分配的参数 JAVA_MEM_OPTS="" BITS=`java -version >& | -bit` if [ -n " ...

  2. PHP测试Mysql数据库连接

    <?php $link = mysqli_connect('localhost', 'username', 'password'); if (!$link) { die('Could not c ...

  3. 【SqlServer】SqlServer中的更新锁(UPDLOCK)

    UPDLOCK.UPDLOCK 的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改.当我们用UPDLOCK来读取记录时可以对取到的记录加上更新锁,从而加 ...

  4. SVProgressHUD在viewDidLoad里无法显示的bug

    两年前已经开始讨论,至今没有解决方案.https://github.com/samvermette/SVProgressHUD/issues/54 [SVProgressHUD show] 的逻辑要放 ...

  5. struts2:数据标签

    目录 数据标签1. a标签2. set标签3. push标签4. bean/param标签5. date标签6. include标签7. url标签8. property标签9. debug标签10. ...

  6. epoll的由来

    reference https://www.zhihu.com/question/20122137 感谢 @静海听风 @蓝形参 数据流有两个重要的参与者: 1.往流中写入数据者 2.从流中读取数据者 ...

  7. 15款基于 jQuery模态对话框

    在数字世界的竞争已大大增加.这就是为什么要确保网络设计的各个方面都是一流的,这是很重要的.从布局到一些非常小的东西,比如对话框,每一件都需要设计得很好.对话框通常被忽视,但它们可能对访问者有很大的影响 ...

  8. Oracle 创建分区表

    --查看数据库中所有用户的分区表 SELECT * FROM DBA_TABLES WHERE PARTITIONED='YES' AND OWNER NOT IN ('SYSTEM','SYS') ...

  9. spring aop 之xml

    1.类库 2.aop概念 一个切面可以有多个切点 3.在方法前后进行aop的测试代码 3.1aop.xml <beans xmlns="http://www.springframewo ...

  10. WebMisSharp,WebMisCentral,企业框架正则表达式规则共享专版

    ElegantWM.WebUI/Application/common/src/Tools.js 欢迎大家贡献更多的正则验证规则,目前支持如下: /*************************** ...