传送门

•题意

  有一棵点数为 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. 【linux配置】在VMware中为Redhat HAT配置本地yum源

    在VMware中为Redhat HAT配置本地yum源 今天准备使用CM安装大数据环境,到需要几台机器都使用同一套yum源才可以,所以想到将Redhat镜像文件拷贝到虚拟机中,在挂起使用,最后通过ht ...

  2. Idea下面无法识别web-inf下lib目录的子目录的jar包,只能直接放lib下面才能识别?

    解决方案一: Ctrl+Alt+Shift+s打开projuect Structure-->Livraries-->➕-->java-->选择对应的lib目录即可! 解决方案二 ...

  3. Kafka 集群安装

    Kafka 集群安装 环境: Linux 7.X kafka_2.x 在linux操作系统中,kafka安装在 /u04/app目录中 1. 下载 # wget https://mirrors.cnn ...

  4. 外贸电子商务网站之Prestashop修改顶部导航

    如修改以上所示顶部导航. 如何在prestashop顶部导航栏添加链接,Module>Top horizontal menu点击进入Configure页面 1,在Settings 中看到 链接 ...

  5. JavaScript--事件委托--冒泡

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. SQL知识总结(1)

    什么是数据库: sql组成: DDL:数据定义语句,有CREATE/DROP等: DML:数据操作语句,有DELETE/UPDATE/INSERT/INSERT等; DQL:数据查询语句,有SELEC ...

  7. php Laravel Thrift使用TMultiplexedProcessor复用端口模式

    thrift的使用中一般是一个Server对应一个Processor和一个Transport,如果有多个服务的话,那必须要启动多个Server,占用多个端口,这种方式显然不是我们想要的,所以thrif ...

  8. Nginx教程(四) Location配置与ReWrite语法 (转)

    Nginx教程(四) Location配置与ReWrite语法 1 Location语法规则 1.1 Location规则 语法规则: location [=|~|~*|^~] /uri/ {… } ...

  9. Leetcode733.Flood Fill图像渲染

    有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间. 给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newCol ...

  10. bzoj1412 狼和羊的故事

    Description “狼爱上羊啊爱的疯狂,谁让他们真爱了一场:狼爱上羊啊并不荒唐,他们说有爱就有方向......” Orez听到这首歌,心想:狼和羊如此和谐,为什么不尝试羊狼合养呢?说干就干! O ...