题目传送门

题目大意:

有一棵点数为 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. AntD01 Angular2整合AntD、Angular2整合Material、利用Angular2,AntD,Material联合打造后台管理系统 ???

    待更新... 2018-5-21 13:53:52 1 环境说明 2 搭建Angular项目 详情参见 -> 点击前往 辅助技能 -> 点击前往 3 创建共享模块 ng g m share ...

  2. OpenCV 2.4.13 installed in Ubuntu 14 and CMakeLists Demo

    1. 配置编译器环境 [compiler] sudo apt-get install build-essential 2. 安装OpenCV的依赖包 [required] -dev pkg-confi ...

  3. 多个if和一个ifelse的区别

    一个程序的要求如下,输入一个学生的数学成绩,如果大于等于60,那么就输出good,如果小于60那么输出not good int a scanf_s("%d",&a) if( ...

  4. Apache apxs命令

    一.简介 apxs是一个为Apache HTTP服务器编译和安装扩展模块的工具,用于编译一个或多个源程序或目标代码文件为动态共享对象,使之可以用由mod_so提供的LoadModule指令在运行时加载 ...

  5. ps怎么修改gif动图播放速度

    ps怎么修改gif动图播放速度 摘自:https://jingyan.baidu.com/article/7e44095302bbdc2fc0e2efad.html photoshop功能很强大,不仅 ...

  6. 登录到 SQL Server 实例

    登录到 SQL Server 实例(命令提示符)   登录到 SQL Server 的默认实例 从命令提示符输入以下命令,使用 Windows 身份验证进行连接:     sqlcmd [ /E ] ...

  7. 实践作业3:白盒测试----小组分工讨论DAY2

    白盒测试需要通过检查软件内部的逻辑结构,对软件中的逻辑路径进行覆盖测试;在程序不同地方设立检查点,检查程序的状态,以确定实际运行状态与预期状态是否一致.我们小组在下课时候,在东九教学楼教师休息室进行了 ...

  8. HttpUploader2 -chrome 45+安装教程

    HttpUploader2-Chrome 45+安装说明 步骤如下: a.先安装HttpUploader2.exe,HttpUploader2.exe为插件集成安装包. b.再安装HttpUpload ...

  9. easyUI Methods

    doc对象转jQuery 对象 $(doc Object); jQuery Object.控件名('方法'[,参数]); options 为该控件的属性 方式一: var opts = $('.eas ...

  10. (转)Asp.Net生命周期系列五

    原文地址:http://www.cnblogs.com/skm-blog/p/3188697.html 如果您看了我的前四篇文章,应该知道目前Http请求已经流到了HttpModule这个程序员手中了 ...