POJ 3498 线段树

题目:http://poj.org/problem?id=3468

题意:在一组数中执行两种操作
"C a b c" means adding c to each of A a, A a+1, ... , A b. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of A a, A a+1, ... , A b.
 
[线段树][延时更新]
   注意:区间长度为s[u].r-s[u].l+1,加1容易被忽略;延时更新s[u].add+=ad,因为是延时更新可能之前存的还没有往后加;
  提示:本题只适用线段树;树状数组能解决的问题线段树都能解决;但线段树是O(nlogn),而树状数组是O(logn),且树状数组的代码实现更简单;
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<queue>
  4 #include<algorithm>
  5 #include<cstring>
  6 #define L(u) (u<<1)
  7 #define R(u) (u<<1|1)
  8 using namespace std;
  9 int a[400000];
 10 int n,q;
 11 struct poin{
 12     int l,r;
 13     long long sum;
 14     long long add;
 15 }s[400000];
 16 void upush(int u)
 17 {
 18     s[u].sum=s[L(u)].sum+s[R(u)].sum;
 19     return ;
 20 }
 21 void downpush(int u)
 22 {
 23     s[L(u)].add+=s[u].add;
 24     s[R(u)].add+=s[u].add;
 25     s[L(u)].sum+=(s[L(u)].r-s[L(u)].l+1)*s[u].add;
 26     s[R(u)].sum+=(s[R(u)].r-s[R(u)].l+1)*s[u].add;
 27     s[u].add=0;
 28     return ;
 29 }
 30 void adding(int u,int left,int right,int ad)
 31 {
 32     if(left<=s[u].l&&right>=s[u].r)
 33     {
 34         s[u].sum+=(s[u].r-s[u].l+1)*ad;
 35         s[u].add+=ad;
 36         return ;    
 37     }
 38     if(s[u].add)downpush(u);
 39     int mid=(s[u].l+s[u].r)>>1;
 40     if(right<=mid)
 41         adding(L(u),left,right,ad);
 42       else if(left>mid)
 43         adding(R(u),left,right,ad);
 44     else 
 45     {
 46         adding(L(u),left,mid,ad);
 47         adding(R(u),mid+1,right,ad);
 48     }
 49     upush(u);
 50 }
 51 long long query(int u,int left,int right)
 52 {
 53     if(left<=s[u].l&&right>=s[u].r)
 54         return s[u].sum;
 55     if(s[u].add)downpush(u);
 56     int mid=(s[u].l+s[u].r)>>1;
 57     if(right<=mid)return query(L(u),left,right);
 58     else if(left>mid)return query(R(u),left,right);
 59     else return (query(L(u),left,mid)+query(R(u),mid+1,right));
 60     upush(u);
 61 }
 62 void build(int u,int left,int right)
 63 {
 64     s[u].l=left;
 65     s[u].r=right;
 66     if(s[u].l==s[u].r)
 67     {
 68         s[u].sum=a[left];
 69         return ;
 70     }
 71     int mid=(left+right)>>1;
 72     build(L(u),left,mid);
 73     build(R(u),mid+1,right);
 74     upush(u);
 75     
 76 }
 77 int main()
 78 {
 79     cin>>n>>q;
 80     for(int i=1;i<=n;i++)
 81     scanf("%d",&a[i]);
 82     build(1,1,n);
 83     for(int i=1;i<=q;i++)
 84     {
 85         char w;
 86         w=getchar();
 87         while(w!='C'&&w!='Q')
 88         w=getchar();
 89         if(w=='C')
 90         {
 91             int y,o,u;
 92             scanf("%d%d%d",&y,&o,&u);
 93             adding(1,y,o,u);
 94         }
 95         if(w=='Q')
 96         {
 97             int y,o;
 98             scanf("%d%d",&y,&o);
 99             long long e=query(1,y,o);
100             cout<<e;
101             printf("\n"); 
102         }
103     }
104     return 0;
105 }

 

 

转载于:https://www.cnblogs.com/nigulasi/p/5665667.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值