P3178 - 树上操作
时间:2021-09-17
本文章向大家介绍P3178 - 树上操作,主要包括P3178 - 树上操作使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
没什么特殊的一道树链剖分板子题,可以作为树剖入门题
操作1单点修改即可
操作2和操作3为树链剖分基础操作
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; #define lid (id << 1) #define rid (id << 1) | 1 typedef long long LL; const int maxn=1e5+10; struct Edge{ int nex; int to; }E[2*maxn]; LL rt,n,m,r,cnt,tot; LL mod=9223372036854775806; LL a[2*maxn]; LL head[maxn]; LL f[maxn];//节点u的父亲节点 LL d[maxn];//节点u的深度 LL size[maxn];//以u为根的子树节点个数 LL son[maxn];//重儿子 LL rk[maxn];//当前dfs标号在树中所对应的节点 LL top[maxn];//当前节点所在链的顶端节点 LL id[maxn];//树中每个节点剖分以后的新编号(决定DFS执行顺序) struct seg_tree { LL l, r; LL lazy; long long sum; } tree[maxn << 2]; void build(LL id, LL l, LL r) { tree[id].l = l; tree[id].r = r; if (l == r) { tree[id].sum = a[rk[l]]; return; } int mid = (l + r) >> 1; build(lid, l, mid); build(rid, mid + 1, r); tree[id].sum = (tree[lid].sum + tree[rid].sum)%mod; } void pushdown(LL id) { if (tree[id].lazy != 0 && tree[id].l != tree[id].r) { LL val = tree[id].lazy; (tree[lid].lazy += val)%=mod; (tree[rid].lazy += val)%=mod; tree[lid].sum += val * (tree[lid].r - tree[lid].l + 1); tree[rid].sum += val * (tree[rid].r - tree[rid].l + 1); tree[id].lazy = 0; } } void add(LL id, LL val,LL l, LL r) { pushdown(id); if (tree[id].l == l && tree[id].r == r) { tree[id].lazy += val; tree[id].sum += val * (r - l + 1); tree[id].sum%=mod; return; } LL mid = (tree[id].l + tree[id].r) >> 1; if (mid >= r) add(lid, val, l, r); else if (mid < l) add(rid, val, l, r); else { add(lid, val, l, mid); add(rid, val, mid + 1, r); } tree[id].sum = (tree[lid].sum + tree[rid].sum)%mod; } long long query(LL id,LL l, LL r) { pushdown(id); if (tree[id].l == l && tree[id].r == r) return tree[id].sum; LL mid = (tree[id].l + tree[id].r) >> 1; if (mid >= r) return query(lid, l, r)%mod; else if (mid < l) return query(rid, l, r)%mod; else return (query(lid, l, mid) + query(rid, mid + 1, r))%mod; } void addedge(int u,int v) { E[++tot].nex=head[u]; E[tot].to=v; head[u]=tot; } void dfs1(int u,int fa,int depth) { f[u]=fa; d[u]=depth; size[u]=1; for(int i=head[u];i;i=E[i].nex) { int v=E[i].to; if(v==fa)continue; dfs1(v,u,depth+1); size[u]+=size[v]; if(size[v]>size[son[u]]) { son[u]=v; }//选取重儿子 } } void dfs2(int u,int t)//t为重链顶端,连接重链,记录dfs,处理top,id,rk以保证dfs序连续 { top[u]=t; id[u]=++cnt;//记录dfs序 rk[cnt]=u;//记录相应dfs序的节点 if(!son[u]) { return; } dfs2(son[u],t); for(int i=head[u];i;i=E[i].nex) { int v=E[i].to; if(v!=son[u]&&v!=f[u]) dfs2(v,v); //轻链底端结点即为重链的顶端 } } LL sum(int x,int y) { LL ans=0; int fx=top[x]; int fy=top[y]; while(top[x]!=top[y]) { if(d[top[x]]<d[top[y]])swap(x,y); (ans+=query(1,id[top[x]],id[x]))%=mod; x=f[top[x]]; } if(id[x]>id[y])swap(x,y); (ans+=query(1,id[x],id[y]))%=mod; return ans; } void update(int x,int y,int c) { while(top[x]!=top[y]) { if(d[top[x]]<d[top[y]]) { swap(x,y); } add(1,c,id[top[x]],id[x]); x=f[top[x]]; } if(id[x]>id[y])swap(x,y); add(1,c,id[x],id[y]); } int main(){ scanf("%lld%lld",&n,&m); r=1; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } for(int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } dfs1(r,0,1); dfs2(r,r); rt=1; build(1,1,n); for(int i=1;i<=m;i++) { LL flag,x,y,z; scanf("%lld",&flag); if(flag==1) { scanf("%lld%lld",&x,&z); add(1,z,id[x],id[x]); } if(flag==3){ scanf("%lld",&x); printf("%lld\n",sum(x,1)); } if(flag==2) { scanf("%lld%lld",&x,&y); add(1,y,id[x],id[x]+size[x]-1); } } return 0; //处理深度d以及父节点f }
原文地址:https://www.cnblogs.com/lemonGJacky/p/15305230.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 深入理解Android Bitmap
- Android基于AlarmManager实现用户在线心跳功能示例
- 详解Android中获取软键盘状态和软键盘高度
- Android流式布局FlowLayout详解
- Linux 专题
- Go语言实现UDP通信
- Android多渠道打包的方法步骤
- Android编程实现压缩图片并加载显示的方法
- Android串口通信封装之OkUSB的示例代码
- Android 中Activity 之间传递参数
- Android开发简单实现摇动动画的方法
- Android 中menu同时显示图标和文字的实现
- android基于SwipeRefreshLayout实现类QQ的侧滑删除
- PopupWindow自定义位置显示的实现代码
- Bootstrap 下拉菜单.dropdown的具体使用方法