题目传送门

题目大意:

有一棵点数为 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. Django框架 之 MTV模型、 基本命令、简单配置

    浏览目录 MTV模型 Django框架前奏 Django基础必备三件套 Djaogo基本命令 MTV模型 Django的MTV分别代表: Model(模型):负责业务对象与数据库的对象(ORM) Te ...

  2. Input的size与maxlength属性的区别

    最近做项目用到input的size和maxlength属性,以前只顾用没有用心去看看这2个标签的区别,今天周末baidu了一下,有所理解.特记录于此!   <p>Name: <inp ...

  3. [GO]冒泡排序的原理和代码实现

    冒泡排序的原理:对于一个数组里所有的元素进行两两比较,发生大于则变换数组下标则为升序排序,发生小于则变换数据下标的则为降序排序 比如给定的数组为[1, -2, 3, -4],对于我们的需求,两两比较后 ...

  4. 最全面的jackson json 技术

    http://www.360doc.com/content/12/0429/09/7656232_207428466.shtml

  5. Django项目运行时出现self.status.split(' ',1)[0], self.bytes_sent,ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接。

    [02/Nov/2018 09:46:51] "GET /new_industry/category HTTP/1.1" 200 2891792 Traceback (most r ...

  6. Graphics 小记

    1.切图 drowg.DrawImage(productImg1, new System.Drawing.Rectangle(30, 30, 300, 300), new System.Drawing ...

  7. 微软和Google的盈利模式对比分析

    一: 微软和Google是世界上最成功科技巨头之一,但他们之间却有着不同的产品和业务,二者的盈利方式也各有不同,本文将分析和探讨的二者盈利模式的异同. 微软的盈利模式 在1975年由大学肄业的Bill ...

  8. C#多线程编程实战1.4终止线程

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

  9. angular 引入第三方库

    第一步 --save:自动写入package.json 第二步: 第三部: 为了让typescript识别$ 第四步:

  10. 洛谷题解 P2865 【[USACO06NOV]路障Roadblocks】

    链接:https://www.luogu.org/problemnew/show/P2865 题目描述 Bessie has moved to a small farm and sometimes e ...