BZOJ 4034"树上操作"(DFS序+线段树)
•题意
有一棵点数为 N 的树,以点 1 为根,且树点有边权。
然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。输出操作 3 对应的答案;
•题解
如果可以将树形结构转化成链式结构,那么,操作 1,2 就可以用线段树来维护;
$1,2,4,4,5,5,2,3,3,1$
定义 $s,e$ 分别记录每个节点在序列中第一次出现的位置和最后一次出现的位置;
那么,第一次出现的位置权值为正,最后一次出现的位置权值为负;
这样的话,就可以通过线段树来维护;
操作 1 就对应线段树中的单点更新操作;
操作 2 就对应线段树中的区间更新操作;
操作 3 就是区间查询操作;
•Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e5+; int n,m;
int a[maxn];
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[maxn<<];
void addEdge(int u,int v)
{
G[num]={v,head[u]};
head[u]=num++;
}
struct Seg
{
int l,r;
ll lazy;
ll sum;
int x;///沿叶子方向的节点个数
int y;///沿根方向的节点个数
int mid(){return l+((r-l)>>);}
void Set(ll val)
{
///如果[l,r]区间的每个节点都增加val
///那么,[l,r]区间中沿叶子方向的x个节点增加+val
///[l,r]区间中沿根方向的y个节点增加-val
lazy += val;
sum += 1ll*(x-y)*val;
}
}seg[maxn<<];
int cnt;
int s[maxn];
int e[maxn];
int vs[maxn<<];
bool g[maxn<<]; void DFS(int u,int f)
{
vs[++cnt]=u;
s[u]=cnt;
g[cnt]=;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(v != f)
DFS(v,u);
}
vs[++cnt]=u;
e[u]=cnt;
g[cnt]=;
}
void pushUp(int pos)
{
seg[pos].x=seg[ls(pos)].x+seg[rs(pos)].x;
seg[pos].y=seg[ls(pos)].y+seg[rs(pos)].y;
seg[pos].sum=seg[ls(pos)].sum+seg[rs(pos)].sum;
}
void pushDown(int pos)
{
ll &lazy=seg[pos].lazy;
if(!lazy)
return ; seg[ls(pos)].Set(lazy);
seg[rs(pos)].Set(lazy); lazy=;
}
void build(int l,int r,int pos)
{
seg[pos]={l,r,,,,}; if(l == r)
{
if(g[l])
{
seg[pos].x++;
seg[pos].sum=a[vs[l]];
}
else
{
seg[pos].y++;
seg[pos].sum=-a[vs[l]];
} return ;
} int mid=seg[pos].mid();
build(l,mid,ls(pos));
build(mid+,r,rs(pos)); pushUp(pos);
}
void update(int pos,int l,int r,int x)
{
if(seg[pos].l == l && seg[pos].r == r)
{
seg[pos].Set(x);
return ;
}
pushDown(pos); int mid=seg[pos].mid();
if(r <= mid)
update(ls(pos),l,r,x);
else if(l > mid)
update(rs(pos),l,r,x);
else
{
update(ls(pos),l,mid,x);
update(rs(pos),mid+,r,x);
}
pushUp(pos);
}
ll query(int pos,int l,int r)
{
if(seg[pos].l == l && seg[pos].r == r)
return seg[pos].sum;
pushDown(pos); int mid=seg[pos].mid();
if(r <= mid)
return query(ls(pos),l,r);
else if(l > mid)
return query(rs(pos),l,r);
else
return query(ls(pos),l,mid)+query(rs(pos),mid+,r);
}
void Solve()
{
cnt=;
DFS(,);
build(,cnt,); while(m--)
{
int op;
scanf("%d",&op);
if(op == )
{
int u,x;
scanf("%d%d",&u,&x);
update(,s[u],s[u],x);
update(,e[u],e[u],x);
}
else if(op == )
{
int u,x;
scanf("%d%d",&u,&x);
update(,s[u],e[u],x);
}
else
{
int u;
scanf("%d",&u);
printf("%lld\n",query(,s[],s[u]));
}
}
}
void Init()
{
num=;
mem(head,-);
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\C++WorkSpace\\in&&out\\contest","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i <= n;++i)
scanf("%d",a+i); Init();
for(int i=;i < n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
Solve(); return ;
}
•变形
此题操作 3 还可改成求解 $u,v$ 路径间的节点权值和;
只需在原来的基础上增加个求解 $LCA$ 的代码即可;
BZOJ 4034"树上操作"(DFS序+线段树)的更多相关文章
- BZOJ4034 [HAOI2015]树上操作+DFS序+线段树
参考:https://www.cnblogs.com/liyinggang/p/5965981.html 题意:是一个数据结构题,树上的,用dfs序,变成线性的: 思路:对于每一个节点x,记录其DFS ...
- BZOJ 3252题解(贪心+dfs序+线段树)
题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...
- [bzoj3306]树——树上倍增+dfs序+线段树
Brief Description 您需要写一种数据结构,支持: 更改一个点的点权 求一个子树的最小点权 换根 Algorithm Design 我们先忽略第三个要求. 看到要求子树的最小点权,我们想 ...
- ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)
题意 链接:https://nanti.jisuanke.com/t/A1998 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根 ...
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...
- DFS序+线段树(bzoj 4034)
题目链接 题目就不多说了. 本题目,可以用dfs序+线段树做:题目给定了一棵树,树上节点告诉了权值.我们可以先将这棵树进行dfs将一棵树变成线性结构:如图 变成这样后,然后就可以用线段树. 操作1:也 ...
- [luoguP3178] [HAOI2015]树上操作(dfs序 + 线段树 || 树链剖分)
传送门 树链剖分固然可以搞. 但还有另一种做法,可以看出,增加一个节点的权值会对以它为根的整棵子树都有影响,相当于给整棵子树增加一个值. 而给以某一节点 x 为根的子树增加一个权值也会影响当前子树,节 ...
- 牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树)
牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树) 链接:https://ac.nowcoder.com/acm/problem/15706 现在需要您来帮忙维护这个名册, ...
- BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树
题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...
- BZOJ1103 [POI2007]大都市meg dfs序 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...
随机推荐
- Ubuntu 安装 setuptools
Setuptools的官方页面 Easily download, build, install, upgrade, and uninstall Python packages 它是一个对python的 ...
- 在Eclipse中添加Tomcat
在Eclipse中开发web或开启web服务需要Tomcat的支持,在添加Tomcat之前要清楚你的Eclipse版本,如果你的Eclipse是javvEE版的就可以直接安装Tomcat,如果不是就需 ...
- 介绍elasticsearch的文件
elasticsearch.yml文件 打开上边的文件,我们看到下面的"集群"名称,节点名称 下图是文件的存储路径和日志路径 下面是监听的地址,默认是本机 下图指的是,集群是怎样搭 ...
- Dubbo报org.I0Itec.zkclient.exception.ZkNoNodeException异常
解决办法就是添加zkclient的jar,maven工程的话增加如下引用: <dependency> <groupId>com.github.sgroschupf< ...
- 【水滴石穿】react-native-template-app
这个也是一个基础项目 地址如下https://github.com/ndlonghi/react-native-template-app 点击登陆跳转到首页 分析代码如 react-native-te ...
- flask 与celery
在flask 中使用celery 是特别简单的,celery官网都没有特别介绍如何使用. 使用celery首先要知道怎么配置celery. 1. 实例化celery celery = Celery ...
- 小爬爬1.requests基础操作
1.requests安装的问题 (1)如果requests没有安装,我们需要先安装这个模块,在cmd安装不了,我们可以在下面的位置,打开的窗体安装requests模块 pip install requ ...
- java把Word文件转成html的字符串返回出去
1.需求是把前端上传的word文件解析出来,生成html的字符串返回给前端去展示,Word里面的图片可以忽略不显示,所以这段代码去掉了解析图片的代码 package com.lieni.core.ut ...
- oralce基本select语句
SELECT [DISTINCT] *|{column1,column2,column3. . .} FROM table l select指定查询哪些列的数据. l column指 ...
- “不是不需要运维工程师,是人人皆是运维”|对话阿里云MVP蒋烁淼(上)
摘要: 与湖畔大学首期学员.阿里云MVP.驻云创始人蒋烁淼面对面 [三位阿里云MVP(驻云CEO.首席架构师.大数据总监)<MVP时间>首次同台授课,“湖畔第一大脑” 蒋烁淼领头线上精讲, ...