zoukankan      html  css  js  c++  java
  • 线段树板子

    线段树练习

    原问题:线段树模板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
    ",ask(1,x,y));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    C# 设置 Excel 条件格式 与 冻结窗口
    Exce折叠效果(数据组合)
    [一点一滴学英语]20050829
    Tencent Messenger
    很有趣的一篇文章:不使用Linux的五大理由
    Tencent Messenger (continued)
    N久没有听过这么搞笑的RAP了
    [一点一滴学英语]20050827
    [Eclipse笔记]SWT真正的优势不是快这么简单
    [一点一滴学英语]20050828
  • 原文地址:https://www.cnblogs.com/LinearODE/p/10152295.html
Copyright © 2011-2022 走看看