传送门

•题意

  有一棵点数为 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序+线段树)的更多相关文章

  1. BZOJ4034 [HAOI2015]树上操作+DFS序+线段树

    参考:https://www.cnblogs.com/liyinggang/p/5965981.html 题意:是一个数据结构题,树上的,用dfs序,变成线性的: 思路:对于每一个节点x,记录其DFS ...

  2. BZOJ 3252题解(贪心+dfs序+线段树)

    题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...

  3. [bzoj3306]树——树上倍增+dfs序+线段树

    Brief Description 您需要写一种数据结构,支持: 更改一个点的点权 求一个子树的最小点权 换根 Algorithm Design 我们先忽略第三个要求. 看到要求子树的最小点权,我们想 ...

  4. ACM-ICPC 2018 沈阳赛区网络预赛 J. Ka Chang(树上分块+dfs序+线段树)

    题意 链接:https://nanti.jisuanke.com/t/A1998 给出一个有根树(根是1),有n个结点.初始的时候每个结点的值都是0.下面有q个操作,操作有两种,操作1.将深度为L(根 ...

  5. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

  6. DFS序+线段树(bzoj 4034)

    题目链接 题目就不多说了. 本题目,可以用dfs序+线段树做:题目给定了一棵树,树上节点告诉了权值.我们可以先将这棵树进行dfs将一棵树变成线性结构:如图 变成这样后,然后就可以用线段树. 操作1:也 ...

  7. [luoguP3178] [HAOI2015]树上操作(dfs序 + 线段树 || 树链剖分)

    传送门 树链剖分固然可以搞. 但还有另一种做法,可以看出,增加一个节点的权值会对以它为根的整棵子树都有影响,相当于给整棵子树增加一个值. 而给以某一节点 x 为根的子树增加一个权值也会影响当前子树,节 ...

  8. 牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树)

    牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树) 链接:https://ac.nowcoder.com/acm/problem/15706 现在需要您来帮忙维护这个名册, ...

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

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

  10. BZOJ1103 [POI2007]大都市meg dfs序 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...

随机推荐

  1. CentOS8/RHEL8--恢复root用户密码及简易加固GRUB

    CentOS8/RHEL8--简易加固GRUB 今天突然想到放在数据中心的虚拟化平台下的Linux服务器,都是采用默认方式安装的,没有设置太多的安全选项,如果有恶意用户重启服务器后,通过GRUB调整启 ...

  2. OpenLayers图层

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head ...

  3. Direct2D 第5篇 绘制图像

    原文:Direct2D 第5篇 绘制图像 我加载的图像是一张透明底PNG图像,背景使用渐变的绿色画刷 #include <windows.h> #include <d2d1.h> ...

  4. Quarz框架学习

    参考博客:https://www.cnblogs.com/zhanghaoliang/p/7886110.html

  5. 洛谷3861八月月赛A题解

    链接 用f[i][j]表示乘积为i的,包含的最大数小于等于j时的方案总数 我们先考虑所用的数为1到n的情况 最后的答案就是f[n][n]-1 转移时考虑f[i][j]可以转移到的状态 显然f[i][j ...

  6. Leetcode883.Projection Area of 3D Shapes三维形体投影面积

    在 N * N 的网格中,我们放置了一些与 x,y,z 三轴对齐的 1 * 1 * 1 立方体. 每个值 v = grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上. 现在,我们查 ...

  7. 怎么用PHP+sqlite3验证登录用户名和密码

    Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象 ...

  8. 春蔚专访--MaxCompute 与 Calcite 的技术和故事

    摘要:2019大数据技术公开课第一季<技术人生专访>,来自阿里云计算平台事业部高级开发工程师雷春蔚向大家讲述了MaxCompute 与 Calcite 的技术和故事. 具体内容包括: 1) ...

  9. 【JZOJ3886】【长郡NOIP2014模拟10.22】道路维护

    CCC 最近徆多人投诉说C国的道路破损程度太大,以至亍无法通行 C国的政府徆重视这件事,但是最近财政有点紧,丌可能将所有的道路都进行维护,所以他们决定按照下述方案进行维护 将C国抽象成一个无向图,定义 ...

  10. typroa 和markdown基操

    目录 标题 一级标题 二级标题 字体 图片 来插入图片,如在同意文件夹上,可直接加图片名 数学公式 编辑表格 标题 一级标题 二级标题 三级标题 无序标题 *加空格,无序标题 也可以使用ctrl = ...