分块——解决区间求和和区间修改的问题

详细的可以参考算法进阶指南P224

问题:

    给定长度为N的数列A;输入指令:

     1.C l r d (把l到r的数字都加d)

     2.Q l r (询问 l到r的数字和)

背景:

    线段树和树状数组可以O(N+log(N))的时间内求得其答案,但是其条件有点苛刻,那么分块就成为了一个不错的选择

 把长度为N的数组分成了以log(N)为基本的各个块;记录每一块的数字,编号,add(增量),sum 这一块的和。

  详细见代码

#include <iostream> 
#include <cstdio> 
#include <fstream> 
#include <algorithm> 
#include <cmath> 
#include <deque> 
#include <vector> 
#include <queue> 
#include <string> 
#include <cstring> 
#include <map> 
#include <stack> 
#include <set>
#include<bitset>
using namespace std;
#define int long long
const int N = 1e5 + 10;
const int INF=0x3f3f3f3f;
const long long LLINF=4e18+5;
typedef long long LL;
typedef pair<int, int> PII;
#define xx first
#define yy second
#define endl '\n' 

struct node
{


//	bool operator<(const node &a) const
//	{
//	}
};
void ClearFloat()
{
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
}

int read() {
    int ret = 0, f = 1;
    char ch = getchar();
    while ('0' > ch || ch > '9') {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        ret = ret * 10 + ch - '0';
        ch = getchar();
    }
    return ret * f;
}
int n,m,t;
int L[N],a[N];
int R[N],pos[N],sum[N],add[N];
void change(int l,int r,int d)
{
    int p=pos[l];
    int q=pos[r];
    if(p==q)
    {
        for(int i=l;i<=r;i++)
        {
            a[i]+=d;
        }
        sum[p]+=d*(r-l+1);
    }
    else
    {
        for(int i=p+1;i<=q-1;i++)
        {
            add[i]+=d;
        }
         for(int i=l;i<=R[p];i++)
        {
            a[i]+=d;
        }
        sum[p]+=d*(R[p]-l+1);
         for(int i=L[q];i<=r;i++)
        {
            a[i]+=d;
        }
        sum[q]+=d*(r-L[q]+1);
    }
}
int query(int l,int r)
{
    int p=pos[l],q=pos[r];
    int ans=0;
    if(p==q)
    {
       for(int i=l;i<=r;i++)ans+=a[i];
       ans+=add[p]*(r-l+1); 
    }
    else
    {
       for(int i=p+1;i<=q-1;i++)
       {
        ans+=sum[i]+add[i]*(R[i]-L[i]+1);
       }
       for(int i=l;i<=R[p];i++)
       {
           ans+=a[i];
       }
       ans+=add[p]*(R[p]-l+1);
       for(int i=R[q];i<=r;i++)
       {
        ans+=a[i];
       }
       ans+=add[q]*(r-R[q]+1);
    }
    return ans;
}
signed main()
{
    ClearFloat();
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    t=sqrt(n);
    for(int i=1;i<=t;i++)
    {
        L[i]=(i-1)*t+1;
        R[i]=i*t;
    }
    if(R[t]<n)t++,L[t]=R[t-1]+1,R[t]=n;
    for(int i=1;i<=t;i++)
    {
        for(int j=L[i];j<=R[i];j++)
        {
           pos[j]=i;
           sum[i]+=a[j];
        }
    }
    while(m--)
    {
        char op[3];
        int l,r,d;
        cin>>op>>l>>r;
        if(op[0]=='C')
        {
            cin>>d;
            change(l,r,d);
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值