poj3468_线段树

题目描述:

   标准的线段树。给出序列操作,分别为对一段区间增值 和 求某一段区间和。

 

解题思路:

   标准的线段树建树,修改和查询操作。这里要注意的是,对修改操作为了避免修改到叶子节点而导致的超时问题,令修改到对应的区间即可,而此时为了保证该区间下的节点能够意识到自己的值已经被修改了——通过对该区间打延时标记来实现。

  附注:有个坑,就是增量得开到64位long long。

 

代码:

#include
#include
#define N 100001

typedef struct{
   int left, right;
   long long tab;
   long long inc;//标记
}CH;

CH segTree[4*N];
int n,q, num[N];
long long sum;


void buildTree(int l, int r, int index){
   segTree[index].left = l;
   segTree[index].right = r;
   segTree[index].tab = 0;
   segTree[index].inc = 0;
   if(l!=r){
      buildTree(l,(l+r)/2,2*index);
      buildTree((l+r)/2+1,r,2*index+1);
   }
}

void changeTree(int l, int r, int t, int index){
   if(segTree[index].left <= l && segTree[index].right >= r){
       //printf("更改区域[%d-%d],增加值%d\n",segTree[index].left,segTree[index].right, (r-l+1)*t);
       segTree[index].tab += (r-l+1)*t;
      
       if(!(segTree[index].left == l && segTree[index].right == r)){ //不是恰好符合的区间,继续更新
           if(l>(segTree[index].left+segTree[index].right)/2){ // in right area
              changeTree(l,r,t,2*index+1);
           }else if(r <= (segTree[index].left+segTree[index].right)/2){
              changeTree(l,r,t,2*index);
           }else{
              changeTree(l,(segTree[index].left+segTree[index].right)/2,t,2*index);
              changeTree((segTree[index].left+segTree[index].right)/2+1,r,t,2*index+1);
           }
       }else{ //恰好符合的区间,添加标记
          // printf("在区域[%d-%d]添加inc=%d\n",segTree[index].left,segTree[index].right,(r-l+1)*t);
           segTree[index].inc += t;
          
           
   }
}

void searchTree(int l, int r, int index){
  
   if(l == segTree[index].left && r == segTree[index].right){
      //printf("在[%d-%d]区域,添加tab=%d\n",l,r,segTree[index].tab);
      sum += segTree[index].tab;
   }else if(l>(segTree[index].left+segTree[index].right)/2){
     // printf("在[%d-%d]区域,添加inc=%d\n",segTree[index].left,segTree[index].right,segTree[index].inc*(r-l+1));
      sum += segTree[index].inc*(r-l+1);
      searchTree(l,r,2*index+1);
   }else if(r <= (segTree[index].left+segTree[index].right)/2){
     // printf("在[%d-%d]区域,添加inc=%d\n",segTree[index].left,segTree[index].right,segTree[index].inc*(r-l+1));
      sum += segTree[index].inc*(r-l+1);
      searchTree(l,r,2*index);
   }else{
     // printf("在[%d-%d]区域,添加inc=%d\n",segTree[index].left,segTree[index].right,segTree[index].inc*(r-l+1));
      sum += segTree[index].inc*(r-l+1);
      searchTree(l,(segTree[index].left+segTree[index].right)/2,2*index);
      searchTree((segTree[index].left+segTree[index].right)/2+1,r,2*index+1);
   }
}

main(){
   char order[2];
   int l, r, c, i;
  
   scanf("%d %d",&n,&q);
   buildTree(1,n,1);
   for(i=1;i<=n;i++){
      scanf("%d",&num[i]);
      changeTree(i,i,num[i],1);
   }
  
  // printf("----------------------------------\n\n");
   for(i=1;i<=q;i++){
      scanf("%s",order);
      if(strcmp(order,"Q")==0){
         sum = 0;
         scanf("%d %d",&l, &r);
         searchTree(l,r,1);
         printf("%lld\n",sum);
      }else{
         scanf("%d %d %d",&l,&r,&c);
         changeTree(l,r,c,1);
      }
   }

   system("pause");
   return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值