博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj4034 树上操作 树链剖分+线段树
阅读量:4344 次
发布时间:2019-06-07

本文共 3108 字,大约阅读时间需要 10 分钟。

题目大意:

有一棵点数为 N 的树,以点 1 为根,且树点有权。然后有 M 个操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
 
思路:
  由于是在刷dfs序专题的时候碰到这题,所以思路被限制了,没想树链剖分的东西,没能做出来,后来发现了一个  ,发现也是可以做的,但是这个做法看不懂。。。留坑
  现在用树链剖分的方法,每个点的权值就是点本身的权值,对于1和2两种操作,直接使用线段树修改就可以了,无非是单点和区间的区别,这里推荐用线段树版本的树链剖分,虽然线段树比树状数组长很多,但是不需要考虑一些边界值加加减减的问题,比赛的时候想那个很可能犯错,用线段树来修改就简单多了(大佬无视这句话)。
  而对于查询操作,用的也是树链剖分往上跳的方法,每次都跳到重链,然后把这段区间的值加起来,(由于是重链,所以dfs序是连续的),这样就可以通过log(n)的时间得到链的权重了。
  所以除了这一点就是个树链剖分的模板题了,线段树直接网上找了一个板子,一发A,做题还是太少。
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
//#include
#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=100010;vector
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<<3],lazy[maxn<<3],size[maxn<<3];inline void dfs_1(int x,int pre){ fa[x] = pre; son[x] = -1; size[x] = 1; deep[x] = deep[pre]+1; for(int i = 0; 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]==-1 || 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] != -1) dfs_2(son[x],root); for(int i = 0; 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]=0;}inline void build(int o,int l,int r){ if(l==r) { sum[o]=(ll)val[fin[l]]; size[o]=1; return; } int mid = (l+r)/2; build(lson,l,mid); build(rson,mid+1,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
r)return; if(l>=L && r<=R) { lazy[o]+=(ll)v; sum[o]+=((ll)size[o])*((ll)v); return; } int mid=(l+r)>>1; update(lson,l,mid,L,R,v); update(rson,mid+1,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
r)return 0; if(l>=L && r<=R)return sum[o]; int mid=(l+r)>>1; return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);}inline ll get(int x){ ll ret = 0; while(top[x]!=1) { ret+=query(1,1,n,l[top[x]],l[x]); x=fa[top[x]]; } ret+=query(1,1,n,1,l[x]); return ret;}int main(){ scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) scanf("%d",&val[i]),sum[i]=i; int u,v; for(int i = 1; i < n; i++) { scanf("%d%d",&u,&v); edge[u].push_back(v); edge[v].push_back(u); } dfs_1(1,0); dfs_2(1,1); build(1,1,n); for(int i = 0; i < m; i++) { scanf("%d%d",&op,&x); if(op==1) { scanf("%d",&v); update(1,1,n,l[x],l[x],v); } if(op==2) { scanf("%d",&v); update(1,1,n,l[x],r[x],v); } if(op==3)printf("%lld\n",get(x)); } return 0;}

 

 

转载于:https://www.cnblogs.com/mountaink/p/9886628.html

你可能感兴趣的文章
取余运算
查看>>
新手小白Linux(Centos6.5)部署java web项目(mysql5.7安装及相关操作)
查看>>
java学习之Runtime
查看>>
行内元素 块状元素 内联块状元素
查看>>
java mysql与.net MSSQL性能测试
查看>>
ruby实现生产者和消费者
查看>>
node.js 之 http 架设
查看>>
MongoDB 备份与还原
查看>>
Oracle启动与关闭数据库实例
查看>>
Spring day01
查看>>
Linux 安装JDK Tomcat MySQL(使用Mac远程访问)
查看>>
hihocoder-1740-替换函数
查看>>
Codeforce Round #219 Div2
查看>>
option value的值可以有空格 再试试吧
查看>>
.htaccess to httpd.conf
查看>>
node.js 基础学习笔记2
查看>>
hadoop中常见元素的解释
查看>>
BZOJ-1497 最大获利
查看>>
4-4 修改文件
查看>>
并发编程(十):AQS
查看>>