BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
题意分析
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
首先上来两次dfs树链剖分问题不大,然后主要是这三个操作分别如何取实现。
先说第一种,点权修改,直接用线段树的点更新就好了。第二个子树修改,貌似树链剖分不能解决子树问题,但是仔细想一下其实是可以的,因为对任意一个节点x,其子树的节点编号都是连续的,原因是在dfs的时候,我们优先遍历这个节点的重儿子形成重链,其次遍历轻儿子形成轻链,所以他的儿子们是连续存储的。而需要修改的区间是[newid[x],newid[x]+size[x]-1],这样利用线段树的区间更新就可已解决了。最后一个询问操作,利用线段树的区间和,完美解决。
直的注意的一点是,在点更新的时候,别忘记有PushDown操作,因为已经打上了lazy标记
代码总览
#include <bits/stdc++.h>
#define ll long long
#define nmax 200820
using namespace std;
int fa[nmax],son[nmax],sz[nmax],newid[nmax],hashback[nmax],dep[nmax],top[nmax],newout[nmax];
int num,tot,head[nmax];
ll data[nmax];
struct edge{
int to;
int next;
}edg[nmax<<2];
struct tre{
int l,r;
ll val,lazy;
int mid(){
return (l+r)>>1;
}
}tree[nmax<<2];
void add(int u, int v){
edg[tot].to = v;
edg[tot].next = head[u];
head[u] = tot++;
}
void dfsFirst(int rt, int f,int d){
dep[rt] = d;
fa[rt] = f;
sz[rt] = 1;
for(int i = head[rt]; i!= -1; i = edg[i].next){
int nxt = edg[i].to;
if(nxt != f){
dfsFirst(nxt,rt,d+1);
sz[rt]+=sz[nxt];
if(son[rt] == -1 || sz[nxt] > sz[son[rt]]){
son[rt] = nxt;
}
}
}
}
void dfsSecond(int rt, int tp){
top[rt] = tp;
newid[rt] = ++num;
hashback[num] = rt;
if(son[rt] == -1) return;
dfsSecond(son[rt],tp);
for(int i = head[rt];i != -1; i = edg[i].next){
int nxt = edg[i].to;
if(nxt != son[rt] && nxt != fa[rt])
dfsSecond(nxt,nxt);
}
}
void init(){
memset(tree,0,sizeof tree);
memset(head,-1,sizeof head);
memset(son,-1,sizeof son);
memset(edg,0,sizeof edg);
memset(hashback,0,sizeof hashback);
memset(data,0,sizeof data);
memset(newid,0,sizeof newid);
tot = num = 0;
}
void PushUp(int rt){
tree[rt].val = tree[rt<<1].val + tree[rt<<1|1].val;
}
void PushDown(int rt){
if(tree[rt].lazy){
tree[rt<<1].lazy += tree[rt].lazy;
tree[rt<<1|1].lazy += tree[rt].lazy;
tree[rt<<1].val += tree[rt].lazy*(ll)(tree[rt<<1].r - tree[rt<<1].l + 1);
tree[rt<<1|1].val +=tree[rt].lazy*(ll)(tree[rt<<1|1].r - tree[rt<<1|1].l + 1);
tree[rt].lazy = 0;
}
}
void Build(int l, int r, int rt){
tree[rt].l = l; tree[rt].r = r;
if(l == r){
tree[rt].val = data[hashback[l]];
return;
}
Build(l,tree[rt].mid(),rt<<1);
Build(tree[rt].mid()+1,r,rt<<1|1);
PushUp(rt);
}
void UpdatePoint(ll val, int pos, int rt){
if(tree[rt].l == tree[rt].r){
tree[rt].val += (ll)val;
return;
}
PushDown(rt);
if(pos <= tree[rt].mid()) UpdatePoint(val,pos,rt<<1);
else UpdatePoint(val,pos,rt<<1|1);
PushUp(rt);
}
void UpdateInterval(ll val, int l, int r, int rt){
if(tree[rt].l >r || tree[rt].r < l) return;
if(tree[rt].l >= l && tree[rt].r <= r){
tree[rt].val += val*(ll)(tree[rt].r - tree[rt].l +1);
tree[rt].lazy += val;
return;
}
PushDown(rt);
UpdateInterval(val,l,r,rt<<1) ;
UpdateInterval(val,l,r,rt<<1|1);
PushUp(rt);
}
ll QuerySUM(int l,int r,int rt){
if(l>tree[rt].r || r<tree[rt].l) return 0;
PushDown(rt);
if(l <= tree[rt].l && tree[rt].r <= r) return tree[rt].val;
return QuerySUM(l,r,rt<<1) + QuerySUM(l,r,rt<<1|1);
}
ll Find_SUM(int x, int y){
int tx = top[x],ty =top[y];
ll ans = 0ll;
while(tx != ty){
if(dep[tx] < dep[ty]){
swap(x,y);
swap(tx,ty);
}
ans += QuerySUM(newid[tx],newid[x],1);
x = fa[tx]; tx = top[x];
}
if(dep[x] > dep[y]) swap(x,y);
ans += QuerySUM(newid[x],newid[y],1);
return ans;
}
int n,m;
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d %d",&n,&m)!=EOF){
init();
for(int i =1;i<=n;++i) scanf("%lld", &data[i]);
int u,v,x,y;
int op;
for(int i =1;i<=n-1;++i){
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
dfsFirst(1,0,1);
dfsSecond(1,1);
Build(1,n,1);
ll val;
for(int i = 0;i<m;++i){
scanf("%d",&op);
if(op == 1){// x add y
scanf("%d %lld",&x,&val);
UpdatePoint(val,newid[x],1);
}else if(op == 2){//x root add y
scanf("%d %lld",&x,&val);
UpdateInterval(val,newid[x],newid[x]+sz[x]-1,1);
}else{// query (1,x)
scanf("%d",&x);
printf("%lld\n",Find_SUM(1,x));
}
}
}
return 0;
}
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )的更多相关文章
- bzoj 4034 [HAOI2015]树上操作 入栈出栈序+线段树 / 树剖 维护到根距离和
题目大意 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- fzu 2082 过路费 (树链剖分+线段树 边权)
Problem 2082 过路费 Accept: 887 Submit: 2881Time Limit: 1000 mSec Memory Limit : 32768 KB Proble ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
- bzoj4034 (树链剖分+线段树)
Problem T2 (bzoj4034 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子 ...
随机推荐
- Ubuntu下载磁力链接,torrent,迅雷链接
用ubuntu下载电影:磁力链接,torrent,迅雷链接 需要软件:Ktorent, Amule 安装软件: sudo apt-get install ktorrent sudo apt-get i ...
- Netty源码分析第4章(pipeline)---->第1节: pipeline的创建
Netty源码分析第四章: pipeline 概述: pipeline, 顾名思义, 就是管道的意思, 在netty中, 事件在pipeline中传输, 用户可以中断事件, 添加自己的事件处理逻辑, ...
- impala 使用记录
在命令行里面直接输入类似下面的语句,就可以执行impala sql语句. impala-shell -q "select * from xxxc limit 10;" 当用pyth ...
- aircrack-ng无线破解实验
查看无线网卡 airmon-ng 开启网卡监听模式 airmon-ng start wlan0 扫描附近的wifi airodump-ng wlan0mon 停止扫描: ctrl c 使用airodu ...
- Java时间格式的使用,bug难时真是坑
很简单的问题,尤其是新手开发,要多自己动手写代码,都说程序猿大都是程序的搬用工,其实不然,好的写手,和差的写手,区别就在是不是会花时间读读代码,并且自己动手实践一下,其实一个程序范这样的错误,绝对是低 ...
- Spring Cloud限流思路及解决方案
转自: http://blog.csdn.net/zl1zl2zl3/article/details/78683855 在高并发的应用中,限流往往是一个绕不开的话题.本文详细探讨在Spring Clo ...
- 第十次PSP
- 第七周psp例行报告
本周psp 本周进度条 代码累积折线图 博文字数累积折线图 饼状图
- mysql/mybatis之合并两个表的查询结果
下面这段sql是把两个表中各自符合条件的count值相加,返回结果是两个之和 SELECT sum(result) FROM ( SELECT COUNT(*) result FROM TEST_A ...
- 冲刺One之站立会议5 /2015-5-18
2015-5-18 服务器部分大体已经完工,现在我们主要是在把登陆界面和服务器组装起来,这个过程是很让人头痛的,以为其中涉及到了很多网络协议.网络编程的知识,由于之前我们没有接触过所以实现起来会觉得很 ...