题目传送门

题目大意:

有一棵点数为 N 的树,以点 1 为根,且树点有权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
 
思路:
  由于是在刷dfs序专题的时候碰到这题,所以思路被限制了,没想树链剖分的东西,没能做出来,后来发现了一个 大佬的博客,发现也是可以做的,但是这个做法看不懂。。。留坑
  现在用树链剖分的方法,每个点的权值就是点本身的权值,对于1和2两种操作,直接使用线段树修改就可以了,无非是单点和区间的区别,这里推荐用线段树版本的树链剖分,虽然线段树比树状数组长很多,但是不需要考虑一些边界值加加减减的问题,比赛的时候想那个很可能犯错,用线段树来修改就简单多了(大佬无视这句话)。
  而对于查询操作,用的也是树链剖分往上跳的方法,每次都跳到重链,然后把这段区间的值加起来,(由于是重链,所以dfs序是连续的),这样就可以通过log(n)的时间得到链的权重了。
  所以除了这一点就是个树链剖分的模板题了,线段树直接网上找了一个板子,一发A,做题还是太少。
#include<cstdio>
#include<algorithm>
//#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<cstring>
#include<queue>
#include<stack>
#include<stdlib.h>
//#include<unordered_map>
#define lson (o<<1)
#define rson ((o<<1)|1)
#define CLR(a,b) memset(a,b,sizeof(a))
#define mkp(a,b) make_pair(a,b)
typedef long long ll;
using namespace std;
const int maxn=;
vector<int> edge[maxn];
int n,m,op,x,tot,val[maxn],l[maxn],r[maxn],deep[maxn],son[maxn],fa[maxn],top[maxn],fin[maxn];
ll sum[maxn<<],lazy[maxn<<],size[maxn<<];
inline void dfs_1(int x,int pre)
{
fa[x] = pre;
son[x] = -;
size[x] = ;
deep[x] = deep[pre]+;
for(int i = ; i < edge[x].size(); i++)
if(edge[x][i] != pre)
{
dfs_1(edge[x][i],x);
size[x] += size[edge[x][i]];
if(son[x]==- || size[edge[x][i]]>size[son[x]]) son[x] = edge[x][i];
}
}
inline void dfs_2(int x,int root)
{
top[x] = root;
l[x] = ++tot;
fin[l[x]] = x;
if(son[x] != -)
dfs_2(son[x],root);
for(int i = ; i < edge[x].size(); i++)
if(edge[x][i] != fa[x] && edge[x][i] != son[x])
dfs_2(edge[x][i],edge[x][i]);
r[x]=tot;
}
inline void maintain(int o,int l,int r)
{
if(l!=r)sum[o]=sum[lson]+sum[rson];
}
inline void pushdown(int o,int l,int r)
{
if(lazy[o])
{
sum[lson]+=size[lson]*lazy[o];
sum[rson]+=size[rson]*lazy[o];
lazy[lson]+=lazy[o];
lazy[rson]+=lazy[o];
}
lazy[o]=;
}
inline void build(int o,int l,int r)
{
if(l==r)
{
sum[o]=(ll)val[fin[l]];
size[o]=;
return;
}
int mid = (l+r)/;
build(lson,l,mid);
build(rson,mid+,r);
maintain(o,l,r);
size[o]=size[lson]+size[rson];
}
inline void update(int o,int l,int r,int L,int R,int v)
{
pushdown(o,l,r);
if(R<l || L>r)return;
if(l>=L && r<=R)
{
lazy[o]+=(ll)v;
sum[o]+=((ll)size[o])*((ll)v);
return;
}
int mid=(l+r)>>;
update(lson,l,mid,L,R,v);
update(rson,mid+,r,L,R,v);
maintain(o,l,r);
}
inline ll query(int o,int l,int r,int L,int R)
{
pushdown(o,l,r);
if(R<l || L>r)return ;
if(l>=L && r<=R)return sum[o];
int mid=(l+r)>>;
return query(lson,l,mid,L,R)+query(rson,mid+,r,L,R);
}
inline ll get(int x)
{
ll ret = ;
while(top[x]!=)
{
ret+=query(,,n,l[top[x]],l[x]);
x=fa[top[x]];
}
ret+=query(,,n,,l[x]);
return ret;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = ; i <= n; i++)
scanf("%d",&val[i]),sum[i]=i;
int u,v;
for(int i = ; i < n; i++)
{
scanf("%d%d",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
dfs_1(,);
dfs_2(,);
build(,,n);
for(int i = ; i < m; i++)
{
scanf("%d%d",&op,&x);
if(op==)
{
scanf("%d",&v);
update(,,n,l[x],l[x],v);
}
if(op==)
{
scanf("%d",&v);
update(,,n,l[x],r[x],v);
}
if(op==)printf("%lld\n",get(x));
}
return ;
}

bzoj4034 树上操作 树链剖分+线段树的更多相关文章

  1. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

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

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

  3. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  4. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

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

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

  6. B20J_3231_[SDOI2014]旅行_树链剖分+线段树

    B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...

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

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

  8. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. fzu 2082 过路费 (树链剖分+线段树 边权)

    Problem 2082 过路费 Accept: 887    Submit: 2881Time Limit: 1000 mSec    Memory Limit : 32768 KB  Proble ...

随机推荐

  1. win7 下安装mysql 整理

    1.去官网下载mysql-5.6.13-winx64.zip包.地址: http://dev.mysql.com/downloads/mysql/5.6.html 2,把安装包解压到自己指定的目录,我 ...

  2. 252. Meeting Rooms 区间会议室

    [抄题]: Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],.. ...

  3. 获取HTML元素位置--js学习笔记

    对于不同的元素,不同的浏览器,offsetParent含义不同,有时,指的是直接包含的元素,有时指的是HTML元素,有时不存在offsetParent. 如果所研究的元素没有offsetParent, ...

  4. 复习action委托

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. QT开发环境

    代码实现界面和槽 代码实现界面和槽 在上述工程的dialog.h中添加如下加黑代码: 加入头文件: #include <QLabel> #include <QLineEdit> ...

  6. 编写高质量代码改善C#程序的157个建议——建议6: 区别readonly和const的使用方法

    建议6: 区别readonly和const的使用方法 很多初学者分不清readonly和const的使用场合.在我看来,要使用const的理由只有一个,那就是效率.但是,在大部分应用情况下, “效率” ...

  7. 关于PHP中的Trait

    今天看PHP框架,看到Trait部分.没见过,好奇查了一下. PHP手册说的是解决多继承的问题.但是一般面向对象的语言中,解决多继承都是通过接口,PHP也有接口.貌似看上去Trait和Interfac ...

  8. Docker 镜像的制作和使用

    镜像 Layer(层) 镜像里的内容是按「层」来组织的,「层」可以复用,一个完整的镜像也可以看做是一个「层」.多个「层」叠加在一起就形成了一个新的镜像,这个镜像也可以作为别的镜像的基础「层」进行更加复 ...

  9. linux下关闭防火墙命令

    今天使用linux虚拟机搭建jenkins,但是在虚拟机内部使用浏览器可以访问jenkins主页,在物理机上却无法访问jenkins主页,查找原因后是因为linux虚拟机没有关闭防火墙,关闭防火墙后, ...

  10. 757. Set Intersection Size At Least Two

    An integer interval [a, b] (for integers a < b) is a set of all consecutive integers from a to b, ...