为了更好的学习线段树,总结一下递归的线段树模板(我就直接一个代码写下来了)
建树~修改~查找
递归线段树:
#include<stdio.h>
#include<string.h>
#include<math.h>
//#include<map>
//#include<set>
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define mod 1000000007
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b)
#define clean(a,b) memset(a,b,sizeof(a))// 水印
ll tree[100100<<2],add[100100<<2];
ll arr[100100],n;
void build_tree(int l,int r,int rt)//l~r,rt为当前节点
{
if(l==r)
{
tree[rt]=arr[l];
return ;
}
int mid=(l+r)>>1;
build_tree(l,mid,rt<<1);
build_tree(mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void updata_dot(int L,int x,int l,int r,int rt)
{//l~r范围内
if(l==r)//单点修改
{
tree[rt]=x;
return ;
}
int mid=(l+r)>>1;
if(L<=mid)
updata_dot(L,x,l,mid,rt<<1);
else
updata_dot(L,x,mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void push_down(int rt,int ln,int rn)//将该节点向下推一个节点
{
if(add[rt])
{
add[rt<<1]=add[rt<<1]+add[rt];
add[rt<<1|1]=add[rt<<1|1]+add[rt];
tree[rt<<1]=add[rt]*ln+tree[rt<<1];
tree[rt<<1|1]=add[rt]*rn+tree[rt<<1|1];
add[rt]=0;
}
}
void updata(int L,int R,int x,int l,int r,int rt)
{
if(l>=L&&r<=R)
{
tree[rt]=tree[rt]+x*(r-l+1);
add[rt]=add[rt]+x;
return ;
}
int mid=(r+l)>>1;
//增加的向下推 ,以rt节点,左边m-l+1个,右边r-mid个
push_down(rt,mid-l+1,r-mid);
if(L<=mid)
updata(L,R,x,l,mid,rt<<1);
if(R>mid)
updata(L,R,x,mid+1,r,rt<<1|1);
tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
ll Query(int L,int R,int l,int r,int rt)
{//区间查询
if(l>=L&&r<=R)
return tree[rt];
int mid=(l+r)>>1;
push_down(rt,mid-l+1,r-mid);
ll res=0;
if(L<=mid)
res=res+Query(L,R,l,mid,rt<<1);
if(R>mid)
res=res+Query(L,R,mid+1,r,rt<<1|1);
return res;
}
int main()
{
build_tree(1,n,1);//建树
updata_dot(L,x,1,n,1);//单点修改
updata(L,R,x,1,n,1);//区间修改
ll res=Query(L,R,1,n,1);//区间查询
}