华师一附中OI组
标题:
基本线段树
[打印本页]
作者:
admin
时间:
2019-11-7 22:36
标题:
基本线段树
线段树是一种常用的数据结构,常常被用于统计区间和,最值等问题,它的基本思想是将区间(l,r)分成(l,m)和(m+1,r)两个基本等长区间,利用和,最大值等的特性(具有一定的传递性)进行统计,这样可以充分利用已经统计的有效信息,减少统计次数。比如整个区间是a1-a10有10个数,我们要多次查询(x,y)区间的数字和问题,我们先建立线段树,用结构体(l,r,s)表示区间(L R)之间的和为S,那么建立线段树如下:
作者:
admin
时间:
2019-11-7 22:36
///先决条件 位操作 树状数组(?)
#include<bits/stdc++.h>
using namespace std;
const int mn=100;
int A[mn]; //原数组
int Sum[mn<<2];//Sum求和,开四倍空间
int Tag[mn<<2];//lazy标记
int n,k,x,y,z;
///左儿子
int ls(int p){return (p<<1);}
///右儿子
int rs(int p){return (p<<1|1);}
//PushUp函数更新节点信息,这里是求和
void PushUp(int p){ Sum[p]=Sum[ls(p)]+Sum[rs(p)];}
void f(int l,int r,int p,int k) ///lr区间的数加上k
{
Tag[p]+=k;
Sum[p]+=k*(r-l+1);
}
void PushDown(int l,int r,int p)
{
int m=(l+r)>>1;
f(l,m,ls(p),Tag[p]);
f(m+1,r,rs(p),Tag[p]);
Tag[p]=0;
}
void Update(int L,int R,int k,int l,int r,int p)
{
if(L<=l && r<=R)
{
Sum[p]+=k*(r-l+1);
Tag[p]+=k;
return;
}
PushDown(l,r,p);
int m=(l+r)>>1;
if(L<=m) Update(L,R,k,l,m,ls(p));
if(R>m) Update(L,R,k,m+1,r,rs(p));
}
//Build函数建立线段树
void Build(int l,int r,int p) //[l,r]表示当前节点区间,p表示当前节点的实际存储位置
{
if(l==r) //若到达叶节点
{
Sum[p]=A[l];//存储A数组的值
return;
}
int m=(l+r)>>1;
Build(l,m,ls(p));
Build(m+1,r,rs(p));
//更新信息
PushUp(p);
}
int Query(int L,int R,int l,int r,int p)
///[L,R]表示操作区间,[l,r]表示当前区间,p当前节点编号
{
if(L<=l && r<=R) return Sum[p];
int m=(l+r)>>1;
int ANS=0;
if(L<=m) ANS+=Query(L,R,l,m,ls(p));
if(R>m) ANS+=Query(L,R,m+1,r,rs(p));
return ANS;
}
int main()
{
n=20;
for (int i=1; i<=20; i++) A[i]=9+i; ///假设20个数字是10-29
Build(1,n,1);
cin>>k; ///进行k次区间修改
while (k--)
{
cin>>x>>y>>z; ///xy区间加上z
Update(x,y,z,1,n,1); ///
cout<<Query(x,y,1,n,1);///输出区间和
}
return 0;
}
复制代码
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2