我是个只会抱dalao的蒟蒻
没错!
我昨天又抱dalao给我讲了线段树
首先线段树是一棵树,一棵完全二叉树
所以就要先来说说什么是完全二叉树
常见的二叉树有满二叉树和完全二叉树
满二叉树是指深度为k且有2 ^ k-1个节点的二叉树
完全二叉树是指最多在最下面两层上其父亲节点下的子节点可以小于2,并且最下层上的结点都集中在该层最左边的位置上
//线段树
//根节点n,左右孩子2*n 2*n+1
1-10 (1)
1-5(2) 6-10 (3)
1-3(4) 4-5(5) 6-8(6) 9-10(7)
1-2 3-3 4-4 5-5 6-7 8-8 9-9 10-10
1-1 2-2 6-6 7-7
首先按照线段树的规律建一棵树
int a[maxn];
ll T[maxn];
void BuildTree(itn l,int r,int rt)
{
if(l == r)//循环到叶子节点的时候把编号填进去
{
T[rt] = a[l];
return ;
}
int mid = (l+r)/2;
BuildTree(l,mid,rt*2);//向左下循环
BuildTree(mid+1,r,rt*2+1);//向右下循环
T[rt] = T[rt*2]+T[rt*2+1];//父亲节点包含左右孩子节点
}
树建好了之后,就可以进行区间求和,单点修改这些操作
//区间求和
// L R 你所要求的区间 L l r R
ll Query(int L,int R,int l,int r,int rt)
{
if(l >= L && r <= R) return T[rt];
int mid = (l+r)/2;
ll sum = 0;
if(mid >= L)//继续往下找
sum += Query(L,R,l,mid,rt*2);
if(R > mid)
sum += Query(L,R,mid+1,r,rt*2+1);
return sum;
}
//单点修改
void Update(int pos,int val,int l,int r,int rt)
{
if(l == r)
{
T[rt] += val;
return ;
}
int mid = (l+r) / 2;
if(pos <= mid)
Update(pos,val,l,mid,rt*2);
else
Update(pos,val,mid+1,r,rt*2+1);
T[rt] = T[rt*2] + T[rt*2+1];
}
以上就是学长给我讲的线段树,下面来写一下自己的理解更新
线段树就是一棵树,我们用结构体来形象的表示这棵树
ll a[maxn];
struct node
{
int l; // 线段的左端点
int r; // 线段的右端点
int val; // 线段上的值
}T[maxn*4];
对于每个结点tree[v],其左孩子为tree[v * 2],右孩子为tree[v * 2+1]
在线段树中,左右孩子分别是父亲结点的子区间
例如父亲结点代表的区间是[l,r]
那么左孩子表示的区间为[l,mid],右孩子表示的区间为[mid+1,r],叶子结点x表示的区间是[x,x]的一个值,即原数组中的一个元素
首先建树工作
void BuildTree(int l,int r,int rt) // 对rt结点进行建立,区间为l~r
{
T[rt].l = l;
T[rt].r = r;
if(l == r){
T[rt].val = a[l];
return ;
}
int mid = (l+r)/2;
BuildTree(l,mid,rt*2);
BuildTree(mid+1,r,rt*2+1);
T[rt].val = T[rt*2].val + T[rt*2+1].val;
}
线段树的主要工作就是更新和查询
const int maxn = 2e6 + 7;
const int mod = 1e9 + 7;
/** keep hungry and keep calm! **/
ll a[maxn];
struct node
{
int l;
int r;
int val;
}T[maxn*4];
void BuildTree(int l,int r,int rt) // 建树
{
T[rt].l = l;
T[rt].r = r;
if(l == r){
T[rt].val = a[l];
return ;
}
int mid = (l+r)/2;
BuildTree(l,mid,rt*2);
BuildTree(mid+1,r,rt*2+1);
T[rt].val = T[rt*2].val + T[rt*2+1].val;
}
void Update(int index,int e,int l,int r,int rt) // 单点修改
{
if(T[rt].l == T[rt].r){
if(T[rt].l == index) T[rt].val += e;
return ;
}
int mid = (T[rt].l + T[rt].r)/2;
if(index <= mid) Update(index,e,l,mid,rt*2);
else Update(index,e,mid+1,r,rt*2+1);
T[rt].val = T[rt*2].val + T[rt*2+1].val;
}
ll Query(int L,int R,int l,int r,itn rt) // 区间查询
{
if(T[rt].l >= L && T[rt].r <= R) return T[rt].val;
int mid = (T[rt].l + T[rt].r)/2;
ll ans = 0;
if(L <= mid) ans += Query(L,R,l,mid,rt*2);
if(R > mid) ans += Query(L,R,mid+1,r,rt*2+1);
return ans;
}
int main(){
int n,m;
n = read(), m = read();
for(int i=1;i<=n;i++){
a[i] = read();
}
BuildTree(1,n,1);
while(m--){
int op,x,y;
scanf("%d%d%d",&op,&x,&y);
if(op == 1){
Update(x,y,1,n,1);
}else{
printf("%lld\n",Query(x,y,1,n,1));
}
}
return 0;
}
const int maxn = 2e6 + 7;
const int mod = 1e9 + 7;
/** keep hungry and keep calm! **/
ll a[maxn];
struct node
{
int l,r;
ll val,add;
}T[4*maxn+2];
void BuildTree(int rt,int l,int r) // 建树
{
T[rt].l = l;
T[rt].r = r;
if(l == r){
T[rt].val = a[l];
return;
}
int mid = (l+r)/2;
BuildTree(rt*2,l,mid);
BuildTree(rt*2+1,mid+1,r);
T[rt].val = T[rt*2].val + T[rt*2+1].val;
}
void spread(int rt)
{
if(T[rt].add != 0)
{
T[rt*2].val += T[rt].add*(T[rt*2].r-T[rt*2].l+1);
T[rt*2+1].val += T[rt].add*(T[rt*2+1].r-T[rt*2+1].l+1);
T[rt*2].add += T[rt].add;
T[rt*2+1].add += T[rt].add;
T[rt].add = 0;
}
}
void Update(int rt,int x,int y,int z) // 区间修改
{
if(x <= T[rt].l && y >= T[rt].r){
T[rt].val += (ll)z*(T[rt].r-T[rt].l+1);
T[rt].add += z;
return;
}
spread(rt);
int mid = (T[rt].l+T[rt].r)/2;
if(x <= mid) Update(rt*2,x,y,z);
if(y > mid) Update(rt*2+1,x,y,z);
T[rt].val = T[rt*2].val + T[rt*2+1].val;
}
ll Query(int rt,int x,int y) // 区间查询
{
if(x <= T[rt].l && y >= T[rt].r) return T[rt].val;
spread(rt);
int mid = (T[rt].l+T[rt].r)/2;
ll ans = 0;
if(x <= mid) ans += Query(rt*2,x,y);
if(y > mid) ans += Query(rt*2+1,x,y);
return ans;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
BuildTree(1,1,n);
while(m--)
{
int op,x,y,z;
scanf("%d",&op);
if(op == 1){
scanf("%d%d%d",&x,&y,&z);
Update(1,x,y,z);
}else{
scanf("%d%d",&x,&y);
printf("%lld\n",Query(1,x,y));
}
}
return 0;
}