洛谷树剖模板题 P3384 | 树链剖分
原题链接
对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树
剩下的就和树剖一样了
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define N 100010 5 typedef long long ll; 6 using namespace std; 7 int ecnt,head[N],son[N],fa[N],sz[N],n,m,r,deep[N],pos[N],indx[N],tot,op,back[N],top[N]; 8 ll val[N],P; 9 struct adj 10 { 11 int nxt,v; 12 }e[2*N]; 13 struct node 14 { 15 int l,r; 16 ll sum,lz; 17 }t[4*N]; 18 void add(int u,int v) 19 { 20 e[++ecnt].v=v; 21 e[ecnt].nxt=head[u]; 22 head[u]=ecnt; 23 e[++ecnt].v=u; 24 e[ecnt].nxt=head[v]; 25 head[v]=ecnt; 26 } 27 void dfs1(int x,int father,int dep) 28 { 29 deep[x]=dep,fa[x]=father,sz[x]=1; 30 for (int i=head[x];i;i=e[i].nxt) 31 { 32 int v=e[i].v; 33 if (fa[x]==v) continue; 34 dfs1(v,x,dep+1); 35 sz[x]+=sz[v]; 36 if (sz[v]>sz[son[x]]) son[x]=v; 37 } 38 } 39 void dfs2(int x,int TOP) 40 { 41 top[x]=TOP; 42 pos[x]=++tot; 43 indx[tot]=x; 44 if (son[x]) dfs2(son[x],TOP); 45 for (int i=head[x];i;i=e[i].nxt) 46 { 47 int v=e[i].v; 48 if (v==fa[x] || v==son[x]) continue; 49 dfs2(v,v); 50 } 51 back[x]=tot; 52 } 53 void pushdown(int p) 54 { 55 if (t[p].l==t[p].r || !t[p].lz) return; 56 int w=t[p].lz; 57 t[p<<1].sum=(t[p<<1].sum+w*(t[p<<1].r-t[p].l+1)%P)%P; 58 t[p<<1|1].sum=(t[p<<1|1].sum+w*(t[p<<1|1].r-t[p<<1|1].l+1)%P)%P; 59 t[p<<1].lz+=w; 60 t[p<<1].lz%=P; 61 t[p<<1|1].lz+=w; 62 t[p<<1|1].lz%=P; 63 t[p].lz=0; 64 } 65 void pushup(int p) 66 { 67 t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%P; 68 } 69 void build(int p,int l,int r) 70 { 71 t[p].l=l,t[p].r=r,t[p].lz=0; 72 if (l!=r) 73 { 74 int mid=l+r>>1; 75 build(p<<1,l,mid); 76 build(p<<1|1,mid+1,r); 77 pushup(p); 78 } 79 else 80 t[p].sum=val[indx[l]]%P; 81 } 82 void modify(int p,int l,int r,int w) 83 { 84 if (t[p].l==l && t[p].r==r) 85 { 87 t[p].sum+=w*(t[p].r-t[p].l+1); 88 t[p].lz+=w; 89 return ; 90 } 91 pushdown(p); 92 int mid=t[p].l+t[p].r>>1; 93 if (r<=mid) modify(p<<1,l,r,w); 94 else if (l>mid) modify(p<<1|1,l,r,w); 95 else modify(p<<1,l,mid,w),modify(p<<1|1,mid+1,r,w); 96 pushup(p); 97 } 98 ll query(int p,int l,int r) 99 { 100 if (t[p].l==l && t[p].r==r) 101 return t[p].sum%P; 102 int mid=t[p].l+t[p].r>>1; 103 pushdown(p); 104 if (r<=mid) return query(p<<1,l,r)%P; 105 if (l>mid) return query(p<<1|1,l,r)%P; 106 return (query(p<<1,l,mid)+query(p<<1|1,mid+1,r))%P; 107 } 108 void pathInc(int u,int v,int w) 109 { 110 while (top[u]!=top[v]) 111 { 112 if (deep[top[u]]<deep[top[v]]) swap(u,v); 113 modify(1,pos[top[u]],pos[u],w); 114 u=fa[top[u]]; 115 } 116 if (deep[u]>deep[v]) swap(u,v); 117 modify(1,pos[u],pos[v],w); 118 } 119 ll pathQuery(int u,int v) 120 { 121 ll ret=0; 122 while (top[u]!=top[v]) 123 { 124 if (deep[top[u]]<deep[top[v]]) swap(u,v); 125 ret=(ret+query(1,pos[top[u]],pos[u]))%P; 126 u=fa[top[u]]; 127 } 128 if (deep[u]>deep[v]) swap(u,v); 129 return (ret+query(1,pos[u],pos[v]))%P; 130 } 131 int main() 132 { 133 scanf("%d%d%d%lld",&n,&m,&r,&P); 134 for (int i=1;i<=n;i++) 135 scanf("%lld",&val[i]); 136 for (int i=1,u,v;i<n;i++) 137 scanf("%d%d",&u,&v),add(u,v); 138 dfs1(r,0,0); 139 dfs2(r,r); 140 build(1,1,n); 141 for (int i=1,x,y,z;i<=m;i++) 142 { 143 scanf("%d",&op); 144 if (op==1) 145 scanf("%d%d%d",&x,&y,&z),pathInc(x,y,z); 146 else if (op==2) 147 scanf("%d%d",&x,&y),printf("%lld\n",pathQuery(x,y)); 148 else if (op==3) 149 scanf("%d%d",&x,&z),modify(1,pos[x],back[x],z); 150 else scanf("%d",&x),printf("%lld\n",query(1,pos[x],back[x])); 151 } 152 return 0; 153 }
转载于:https://www.cnblogs.com/mrsheep/p/7892142.html
洛谷树剖模板题 P3384 | 树链剖分相关推荐
- 洛谷 P3373 【模板】线段树 2 题解
洛谷 P3373 [模板]线段树 2 题解 题面 题目链接:[戳这里](https://www.luogu.org/problemnew/show/P3373) 题目描述 输入输出格式 输入输出样例 ...
- 洛谷 P3373 【模板】线段树 2 解题报告
P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上\(x\) 2.将某区间每一个数加上\(x\) 3.求出某区间每一个数的和 输入输出格式 ...
- 洛谷 P3372 【模板】线段树 1(线段树区间加区间找)
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入格式 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含 ...
- 洛谷 P3372 【模板】线段树 1
文章目录 题目描述 输入格式 输出格式 输入输出样例 说明 [样例解释] AC的C++代码(结合注释理解) 题目描述 如题,已知一个数列,你需要进行下面两种操作: 将某区间每一个数加上k. 求出某区间 ...
- 洛谷 P5057 [CQOI2006]简单题(树状数组)
嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...
- 洛谷 P3373 【模板】线段树 2(线段树区间乘、加 区间查找)
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式 第一行包含三个整数N.M.P,分别表示该数列数字的 ...
- 洛谷 3373 【模板】线段树 2
题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别 ...
- 洛谷-3373 【模板】线段树 2
题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含三个整数N.M.P,分别 ...
- 洛谷 P3373 【模板】线段树 2
https://www.luogu.org/problem/P3373 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每 ...
最新文章
- 分享几个用 Python 给图片添加水印的方法,简单实用
- 多级反馈队列列算法的优点
- How to solve random black screen on macOS Sierra
- ListView的Columns自适应内部文字
- [Winform]安装在C盘,无操作权限的一个解决办法
- mysql一对多代码_MySQL实现一对多查询的代码示例
- 分支-08. 高速公路超速处罚
- MOSS 2007基础:内容类型(Content Type)之二
- Subversion under Linux [Reprint]
- dataimagepng php_PHP decode data:image/png;base64
- 【机器学习】鸢尾花数据探索
- 设计模式--工厂模式(c++)
- Codeforces Round #FF(255) DIV2
- opengl 遇到的基础问题
- springboot项目去除druid监控的广告超链接等
- 桌面快捷方式图标不能删除的原因以及处理方法
- 中国车牌号的分类说明识别及含义
- linux系统update和upgrade区别
- 10张剪纸风格2021牛年祝福海报
- 关于博客的论文php,基于php的个人博客系统毕业设计论文
热门文章
- 重启php-fpm的方法
- Oracle lower() Upper()函数
- leetcode练习——数组篇(1)(std::ios::sync_with_stdio(false);std::cin.tie(nullptr);)
- OpenDDS通讯中rtps_discovery对等发现的基本配置和说明
- 《App后台开发运维与架构实践》第3章 App后台核心技术
- 小程序学习(一):点击爱心变色 -- 最简单的事件实现
- 雪碧图sprity 合并多图使用心得
- 疯狂java学习笔记1023---线程的同步
- 服务器内存延迟,内存带宽、延迟性能测试
- 北海市计算机等级考试,2021上半年北海市计算机二级报名时间|网上报名入口【已开通】...