题面: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. sql server 多表关联更新 update

    update a set a.KSMC = b.name from JC_KSXXB a inner join chisdb_ymyy..zd_unit_code b on a.KSDM = b.co ...

  2. C#:文件夹匹配

    //文件夹匹配:对比文件夹,相同的目录结构.所有文件名称小写相同,制定文件外的MD5值相同 ,则两个文件夹匹配成功! /// <summary> /// 批量匹配书籍H5资源包 /// & ...

  3. Atitit.pagging  翻页功能解决方案专题 与 目录大纲 v3 r44.docx

    Atitit.pagging  翻页功能解决方案专题 与 目录大纲 v3 r44.docx 1.1. 翻页的重要意义1 1.2. Dep废弃文档   paip.js翻页分页pageing组件.txt1 ...

  4. Pitch detection algorithm(基音搜索算法)PDA相关链接

    第一:维基百科 http://en.wikipedia.org/wiki/Pitch_estimation 简要系统介绍了基音估计算法的分类和一些链接,论文 第二:http://ws2.bingham ...

  5. PHP更改自动加载的顺序

    composer的锅 自从PHPer们用上了composer后,对于传统的加载方式倒是不会用了,可谓是"收之东隅,失之桑榆". 下面说一下怎么改变加载顺序来覆写Laravel中的h ...

  6. Threads vs. Tasks

    Posted on Friday, October 11, 2013 .Net has three low-level mechanisms to run code in parallel: Thre ...

  7. 稍稍解读下ThreadPoolExecutor

    # 说说ThreadPoolExecutor ## 认识 先来看看它所在的架构体系: ```java package java.util.concurrent; public interface Ex ...

  8. ubuntu 原生迅雷

    https://github.com/Xinkai/XwareDesktop/wiki

  9. Ubuntu16.04搭建Postfix作为SMTP服务器

    一.DNS配置 类型 名称  值  TTL   A mail  128.199.254.32  1小时  MX  @ mail.example.com(优先:10) 1小时  TXT @  v=spf ...

  10. Java Annotation 应用 -- 导出Excel表格

    相关知识链接: Introspector(内省) POI 1.声明注解 package com.ciic.component.excel; import java.lang.annotation.El ...