题面: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. IASetIndexBuffer Offset

    这个Offset官方解释是:Offset (in bytes) from the start of the index buffer to the first index to use. 翻译成中文就 ...

  2. 简单的redis测试

    //这个方法会多一次 public function testRedisList(){ $num = 10; $user_id = uniqid(); //直接链接本地的redis $redis = ...

  3. SSD卡对mongodb的影响

    结论 1:SSD卡显著改善磁盘IO,io占用在50%以下 2:SSD卡使mongodb性能稳定.在200并发,数据量是内存5倍的情况下仍然保证每秒1500次插入和4500次查询.     数据如下: ...

  4. Swift Guard 守护

    前言 guard 语句和 if 语句有点类似,都是根据其关键字之后的表达式的布尔值决定下一步执行什么. guard 语句只会有一个代码块,不像 if 语句可以 if else 多个代码块. guard ...

  5. 【转载】ASP.NET MVC的过滤器【Filters】

    文章来自: http://www.cnblogs.com/HopeGi/p/3342083.html 这篇对Filters讲的很详细.正好我自己也不用写了,真的很棒的一篇文章 APS.NET MVC中 ...

  6. LaTeX语法笔记

    1.单词之间用空格分隔,段落之间用一整空行分隔,但是,如果在多输入空格或者空行也没有用处,系统还是把它当做一个空格或空行. 2.双引号:左侧用``(键盘左上角那个符号),右侧用'',即: ``'' , ...

  7. 基音检测算法的性能:Performance Evaluation of Pitch Detection Algorithms

    http://access.feld.cvut.cz/view.php?cisloclanku=2009060001 Vydáno dne 02. 06. 2009 (15123 přečtení) ...

  8. 奇怪的Excel导入问题,OleDbException (0x80004005): 未指定的错误

    windows server 2008 的安全性做的比较好,首先进入系统盘(一般都是C:\),点击工具--文件夹选项--查看,把“使用共享向导(推荐)”的勾去掉,把“隐藏受保护的操作系统文件(推荐)” ...

  9. C++ 成员函数赋值给C 的函数指针的采坑录

    最近做一个banana Pi M1+的硬解码器封装成类的时候,由于是依赖ffmpeg的,而ffmpeg是C 实现的,本来demo 都是直接用C写的,测试也没有问题,想着封装也不会有问题,至少自己对C+ ...

  10. Install elasticsearch-head: – for Elasticsearch 5.x

    Running as a plugin of Elasticsearch Install elasticsearch-head:– for Elasticsearch 5.x:site plugins ...