线段树入门 理解

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
int n,m;
int a[100001]; // 叶子结点数N
__int64 ans;

struct
{
 int l,r;
 __int64 sum,add; //__int64 
}tree[400000]; //数中所有结点数量大概为 2^2*N 层数logN  h=logN+1 或+2  每次插入更新不超过 O(logN)

void build(int l,int r,int i)
{
 tree[i].l = l;
 tree[i].r = r;
 tree[i].add = 0;
 if(l == r)
 {
  tree[i].sum = a[l]; //叶子结点的值=输入数组的值
  return ;
 }
 int mid = (l+r)/2;
 build(l,mid,2*i);
 build(mid+1,r,2*i+1);
 tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;
}

void updata(int l,int r,int add,int i)
{
 if(tree[i].l > r || tree[i].r < l)
  return ;
 if(tree[i].l >= l && tree[i].r <= r)
 {
  tree[i].sum += (tree[i].r-tree[i].l+1)*add;
  tree[i].add += add;
  return ; //lazy 只加到分解唯一的子区间
 }
 if(tree[i].add) //lazy 边更新边维护 为了确保 孩子的 add和 sum正确 必须更新 且更新完后 当前add=0 (更新到最底)的意思 
 {
  tree[2*i].sum += (tree[2*i].r-tree[2*i].l+1)*tree[i].add;
  tree[2*i].add += tree[i].add;
  tree[2*i+1].sum += (tree[2*i+1].r-tree[2*i+1].l+1)*tree[i].add;
  tree[2*i+1].add += tree[i].add;
  tree[i].add = 0;
 }
 updata(l,r,add,2*i);
 updata(l,r,add,2*i+1);
 tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;
}

void query(int l,int r,int i)
{
 if(tree[i].l > r || tree[i].r < l)
  return ;
 if(tree[i].l >= l && tree[i].r <= r)
 {
  ans += tree[i].sum;
  return ;
 }
 if(tree[i].add) //lazy 边查询边维护 
 {
  tree[2*i].sum += (tree[2*i].r-tree[2*i].l+1)*tree[i].add;
  tree[2*i].add += tree[i].add;
  tree[2*i+1].sum += (tree[2*i+1].r-tree[2*i+1].l+1)*tree[i].add;
  tree[2*i+1].add += tree[i].add;
  tree[i].add = 0;
 }
 query(l,r,2*i);
 query(l,r,2*i+1);
 tree[i].sum = tree[2*i].sum + tree[2*i+1].sum;
}

int main()
{
 //freopen("in.txt","r",stdin);
 int i,x,y,z;
 char c;
 while(scanf("%d%d",&n,&m)!=EOF)
 {
  for(i=1;i<=n;i++)
   scanf("%d",&a[i]);
  build(1,n,1);
  scanf("%*c");
  for(i=1;i<=m;i++)
  {
   scanf("%c",&c);
   if(c == 'Q')
   {
    scanf("%d%d%*c",&x,&y);
    ans = 0;
    query(x,y,1);
    printf("%I64d\n",ans);
   }
   else
   {
    scanf("%d%d%d%*c",&x,&y,&z);
    updata(x,y,z,1);
   }
  }
 }
 return 0;
}

扒了一线段树代码 注释作分析



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值