线段树板子

线段树练习

原问题:线段树模板1

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式:

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3或4个整数,表示一个操作,具体如下:

操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:

输出包含若干行整数,即为所有操作2的结果。

代码(数组)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int Nmax=100010;
const int Mmax=100010;

inline int lp(int p)
{
    return p<<1;
}
inline int rp(int p)
{
    return p<<1|1;
}

struct Sg{
    int l,r;
    int p;
    long long data,add;
    Sg()
        {
            add=0;
        }
};
Sg T[Nmax*4];
int a[Nmax];

#define data(p) T[p].data
#define l(p) T[p].l
#define r(p) T[p].r
#define add(p) T[p].add
int M,N;

inline int len(int a,int b)
{
    return b-a+1;
}

void build(int p,int l,int r)
{
    l(p)=l;r(p)=r;
    if(l==r)
    {
        data(p)=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lp(p),l,mid);
    build(rp(p),mid+1,r);
    data(p)=data(p*2)+data(p*2+1);
    return;
}

void spread(int p)
{
    if(add(p))
    {
        data(lp(p))+=add(p)*len(l(lp(p)),r(lp(p)));
        data(rp(p))+=add(p)*len(l(rp(p)),r(rp(p)));
                                add(lp(p))+=add(p);
                                add(rp(p))+=add(p);
        add(p)=0;
    }
}
void update(int p,int l,int r,int x)
{
    if(l<=l(p) && r(p)<=r)
    {
        data(p)+=(long long)x*(len(l(p),r(p)));
        add(p)+=x;
        return;
    }
    spread(p);
    int mid=(l(p)+r(p))>>1;
    if(l<=mid)
        update(lp(p),l,r,x);
    if(mid<r)
        update(rp(p),l,r,x);
    data(p)=data(lp(p))+data(rp(p));
    return;
}
long long ask(int p,int l,int r)
{
    if(l<=l(p) && r(p)<=r)
        return data(p);
    spread(p);
    int mid=(l(p)+r(p))>>1;
    long long tmp=0;
    if(l<=mid)
        tmp+=ask(lp(p),l,r);
    if(mid<r)
        tmp+=ask(rp(p),l,r);
 	return tmp;
}
int main()
{
    scanf("%d %d",&N,&M);
    for(register int i=1;i<=N;i++)
    {
        scanf("%d",&a[i]);
    }
    build(1,1,N);
    for(register int i=1;i<=M;i++)
    {
        int c,x,y,k;
        scanf("%d %d %d",&c,&x,&y);
        if(c==1)
        {
            scanf("%d",&k);
            update(1,x,y,k);
        }
        else if(c==2)
        {
            printf("%lld\n",ask(1,x,y));
        }
    }
    return 0;
}
posted @ 2018-12-20 21:01  LinearODE  阅读(140)  评论(0编辑  收藏  举报