线段树模板
Posted zmachine
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树模板相关的知识,希望对你有一定的参考价值。
题目描述
如题,已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 kk。
- 求出某区间每一个数的和。
输入格式
第一行包含两个整数 n, mn,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含 33 或 44 个整数,表示一个操作,具体如下:
1 x y k
:将区间 [x, y][x,y] 内每个数加上 kk。2 x y
:输出区间 [x, y][x,y] 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
#include <bits/stdc++.h> typedef long long int LL; using namespace std; const int maxn = 1e5+5; LL n,m; //n数列数字的个数,m为操作的总个数 LL num[maxn],ans[maxn<<2],tag[maxn<<2]; //num[i]存储原始序列的值, //返回左孩子 LL ls(LL p){ return p<<1; } //返回右孩子 LL rs(LL p){ return p<<1|1; } void push_up(LL p){ ans[p] = ans[ls(p)]+ans[rs(p)]; }//不断向上进行相应的更新操作 void build(LL p,LL l,LL r){ //p表示区间段节点的编号 tag[p] =0; //lazy tag的初始化处理部分 if(l==r){ ans[p] = num[l]; return; } //左右区间相等,到达叶子节点部分,被赋予实际的值 //借助二叉树,二分来降低相应的时间复杂度 LL mid = (l+r)>>1; build(ls(p),l,mid); build(rs(p),mid+1,r); push_up(p);//通过子节点来维护父节点的相应的值,在回溯的时候来进行相应的实现 } //区间修改部分的处理 //对于区间内的每个数均加k操作 //f用来记录当前节点所代表的区间信息,然后辅助向下进行相应的更新 void f(LL p,LL l,LL r,LL k){ tag[p] = tag[p]+k; ans[p] += k*(r-l+1);//区间内元素个数*k } void push_down(LL p,LL l,LL r){ //将tag信息传递到其子节点,并将自身节点的信息清零 LL mid = (l+r)>>1; f(ls(p),l,mid,tag[p]); f(rs(p),mid+1,r,tag[p]); tag[p] = 0; //每次更新两个儿子节点的信息,并将相应的信息继续往下传递 } //注意单点修改是 void update(LL nl,LL nr,LL l,LL r, LL p,LL k){ //nl-nr为需要进行修改的区间 //l-r当前节点存储的区间 //p,k节点的编号和需要改变的增量 if(nl<=l&&nr>=r){ //当前区间被需要更行的区间包含 //tag的优势显示在这,达到递归的终结位置 ans[p]+=k*(r-l+1); tag[p]+=k; return; } push_down(p,l,r); //将更改信息下传下去 LL mid = (l+r)>>1; if(nl<=mid) update(nl,nr,l,mid,ls(p),k); if(nr>mid) update(nl,nr,mid+1,r,rs(p),k); //回溯的时候更新ans的值 push_up(p); } //查询操作 LL query(LL q_x,LL q_y,LL l,LL r,LL p){ LL res = 0; if(q_x<=l && q_y>=r) return ans[p]; //当前节点表示的区间被包含 LL mid = (l+r)>>1; push_down(p,l,r);//将之前没有处理的lazy tag向下传递,进行更新并求解 if(q_x<=mid) res+=query(q_x,q_y,l,mid,ls(p)); if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rs(p)); return res; } int main(){ scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++){ scanf("%lld",&num[i]); } build(1,1,n); //以1为根节点,开始建立相应的数 LL choice,x,y,k; while(m--){ scanf("%lld",&choice); switch(choice){ case 1: scanf("%lld%lld%lld",&x,&y,&k); update(x,y,1,n,1,k); break; case 2: scanf("%lld%lld",&x,&y); printf("%lld\\n",query(x,y,1,n,1)); } } return 0; }
以上是关于线段树模板的主要内容,如果未能解决你的问题,请参考以下文章