POJ 3468-线段数区间更新

POJ 3468

You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.
题目大意:给你一堆数,在区间里进行各种操作,询问区间的和、注意sum、和seg的数据类型是long long
真的是艰难,经历了3个小时终于A掉了,不过还是值得的。这样一来对线段树的区间更新认识更加深刻了,回来再把区间更新的原理写出来吧,虽然不是很困,但是时间真的有点晚了,我还有点饿
区间更新、区间求和更新延迟标记时注意

标记的叠加、叠加、叠加…省略无数次叠加

Pushdown

void Pushdown(int l,int r,int i)
{//操作结果延迟标记下压子区间
 //同时更新子区间区间的sum
    if(tree[i].seg==0)
        return ;
    int m=(l+r)>>1;
    tree[i<<1].seg+=tree[i].seg;//注意这里是叠加
    tree[i<<1].sum+=tree[i].seg*(m-l+1);
    tree[i<<1|1].seg+=tree[i].seg;
    tree[i<<1|1].sum+=tree[i].seg*(r-m);
    tree[i].seg=0;//清楚延迟标记
}

Update

void Update(int L,int R,int l,int r,int i,long long e)
{ //操作结果将目标区间打上延迟标记,更新路径上的sum
       if(L<=l&&R>=r)
       {
           tree[i].seg+=e;//这里是细节
           tree[i].sum+=(long long)(e*(r-l+1));
           return;
       }
       Pushdown(l,r,i);
       int m=(l+r)>>1;
       if(L<=m)
        Update(L,R,lson,e);
       if(R>m)
        Update(L,R,rson,e);
       Pushup(i);
}
#include
#include
#include
#define lson l,m,i<<1
#define rson m+1,r,i<<1|1
using namespace std;
const int maxn=100005;
struct node
{
    int left,right;
    long long sum;
    long long seg;
}tree[maxn<<2];
void Pushup(int i)
{
    tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}

void Pushdown(int l,int r,int i)
{//操作结果延迟标记下压子区间
 //同时更新子区间区间的sum
    if(tree[i].seg==0)
        return ;
    int m=(l+r)>>1;
    tree[i<<1].seg+=tree[i].seg;//注意这里是叠加
    tree[i<<1].sum+=tree[i].seg*(m-l+1);
    tree[i<<1|1].seg+=tree[i].seg;
    tree[i<<1|1].sum+=tree[i].seg*(r-m);
    tree[i].seg=0;//清楚延迟标记
}

void Build(int l,int r,int i)
{
    tree[i].left=l;
    tree[i].right=r;
    if(l==r)
    {
        scanf("%lld",&tree[i].sum);
        return ;
    }
    int m=(l+r)>>1;
    Build(lson);
    Build(rson);
    Pushup(i);
}

void Update(int L,int R,int l,int r,int i,long long e)
{ //操作结果将目标区间打上延迟标记,更新路径上的sum
       if(L<=l&&R>=r)
       {
           tree[i].seg+=e;//这里是细节
           tree[i].sum+=(long long)(e*(r-l+1));
           return;
       }
       Pushdown(l,r,i);
       int m=(l+r)>>1;
       if(L<=m)
        Update(L,R,lson,e);
       if(R>m)
        Update(L,R,rson,e);
       Pushup(i);
}
long long Query(int L,int R,int l,int r,int i)
{//操作结果 求区间和、跟新途中延迟标记
    if(L<=l&&R>=r)
    {
        return tree[i].sum;
    }
    long long ans=0;
    Pushdown(l,r,i);
    int m=(l+r)>>1;
    if(L<=m)
        ans+=Query(L,R,lson);
    if(R>m)
        ans+=Query(L,R,rson);
    return ans;
}
 int main()
 {
     memset(tree,0,sizeof(tree));
     int N,Q;
     cin>>N>>Q;
     Build(1,N,1);
     for(int j=1;j<=Q;j++)
     {
         int a,b,c;
         char str;
         cin>>str;
         if(str=='Q')
         {
             cin>>a>>b;
          cout<1,N,1)<if(str=='C')
         {
             cin>>a>>b>>c;
             Update(a,b,1,N,1,c);
         }
     }

     return 0;
 }

你可能感兴趣的:(线段树)