uestc oj 1225 A Simple Problem with Integers

A Simple Problem with Integers
   
这一题就是简单的线段树+懒操作可以解决的。更改区间 查询区间和 
由于数据时10^9数量级的 所以sum,a这个操作数要定义成long long型的 其实我在写的过程中把 增加值c也写成long long 了 其实没必要的 不过也没有浪费多少空间的。
    其中sum是区间和 a是懒操作标记 就是这个区间上的数都要加上的值  (在search 和update的时候都要进行懒操作)
    普通的建树初始化查询和更新,树节点当中存储的是左边界 右边界 区间和 以及懒操作标记
    懒操作标记的主要目的就是在更新的时候向下更新  向上更新的操作可以由递归完成的(如注释)
    因为这次在查询的时候会不断向下递归查询,与hotel题目不同,需要在search的时候进行更新懒操作。
    在更新懒操作标记的时候要给sum 加上 (区间元素个数  * 懒操作数)另外还要向下更新子树结点的懒操作数
    还有就是在写这一题之前没有了解牛逼的宏定义 写的代码有点乱的,当时调的也费劲 
    if(tree[id].l==l&&tree[id].r==r) 至于这里是写成这样还是写成if(tree[id].l>=l&&tree[id].r<=r)  我分析了下其实都是差不多的
    其实在查询到一个节点的时候只有两种情况 查询的区间比他小 要么一样大 不可能比他还大 因为若比他大 在上一个父节点的时候已经被拆开了(分别走向左右子树)
    其余的感觉没什么可以讲得了,总不能把建树过程详细叙述一遍吧? 嘿嘿 


时间复杂度:线段树的修改操作和查询操作都是logN,一共执行Q次修改和查询操作  故时间复杂度为O(QlogN)
空间复杂度:线段树用堆实现   故空间复杂度为O(3N) 有种说法是 3N属于正常,4N属于保守,2N属于拼人品
当然本题用了4N的


#include<cstdio>
#include<cstring>
using namespace std;
#define N 100005


int v[N];


char f[5];
int num1,num2,num3,i,h,k;long long p;


struct node
  {
    long long  sum,a;
    int l;
    int r;
  }tree[N*4];


void build(int id,int l,int r)
{
 tree[id].l = l;
 tree[id].r = r;
 tree[id].a = 0;
 if(l==r)
 {
     tree[id].sum=v[l];
     return;
 }


 else
    {
     int mid = (l+r)>>1;
     build(2*id,l,mid);
     build(2*id+1,mid+1,r);
     tree[id].sum = tree[id*2].sum + tree[id*2+1].sum;
    }
}


long long  search(int id,int l,int r)
{
   if(tree[id].l==l&&tree[id].r==r)
     {


       return tree[id].sum;
     }
   if(tree[id].a)  //完成向下更新  
    {
        tree[2*id].a +=tree[id].a;
        tree[2*id+1].a+=tree[id].a;
        tree[2*id].sum +=tree[id].a*(tree[id*2].r - tree[id*2].l+1);
        tree[2*id+1].sum+=(tree[id].a)*(tree[2*id+1].r - tree[2*id+1].l+1);
        tree[id].a = 0;
    }
    int mid = (tree[id].l+tree[id].r)>>1;
    if(l>mid)
      return search(2*id+1,l,r);
    else if(r<=mid)
          return search(2*id,l,r);
     else
     return search(2*id,l,mid)+search(2*id+1,mid+1,r);


}


void update(int id,int l,int r,long long val)
{
     if(tree[id].l==l&&tree[id].r==r)
     {
        tree[id].sum +=(tree[id].r - tree[id].l+1)*val;
        tree[id].a += val;
        return;
     }
     if(tree[id].a)   //完成向下更新
     {
         tree[id*2].a +=tree[id].a;
         tree[id*2+1].a+=tree[id].a;
         tree[2*id].sum+=(tree[2*id].r - tree[2*id].l+1)*tree[id].a;
         tree[2*id+1].sum += (tree[2*id+1].r - tree[2*id+1].l+1)*tree[id].a;
         tree[id].a = 0;
     }
     int mid = (tree[id].l+tree[id].r)>>1;
     if(l>mid)
       update(2*id+1,l,r,val);
     else if(r<=mid)
        update(2*id,l,r,val);
      else
       {
           update(2*id,l,mid,val);
           update(2*id+1,mid+1,r,val);
       }
     tree[id].sum = tree[id*2].sum + tree[2*id+1].sum;  //完成向上更新的主要操作
}


int main()
{
    while(scanf("%d%d",&num1,&num2)==2)
    {
        memset(v,0,sizeof(v));
        for(i=1;i<=num1;i++)
            scanf("%d",&v[i]);


        build(1,1,num1);
        while(num2--)
        {
           scanf("%s",f);
           if(f[0]=='Q')
           {
            scanf("%d%d",&h,&k);
            printf("%lld\n",search(1,h,k));
           }
           else if(f[0]=='C')
          {
            scanf("%d%d%lld",&h,&k,&p);
            if(p==0) continue;
            update(1,h,k,p);
          }
        }




    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值