分块---A Simple Problem with Integers

Description


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

 

分块

#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 100010
using namespace std;
ll a[N],sum[N],add[N];
int L[N],R[N],d;
int pos[N];
int n,m,t,l,r;
char op[3];
void change(int l,int r,long long d)
{
    int p=pos[l],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);
        //暴力局部修改
    }
}
ll ask(int l,int r)
{
    int p=pos[l],q=pos[r];
    ll 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=L[q];i<=r;i++) ans+=a[i];
        ans+=add[q]*(r-L[q]+1);
        //暴力局部累加
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lld",&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];//计算段落和
      }
    for(int i=1;i<=m;i++)
    {
        scanf("%s %d %d",op,&l,&r);
        if(op[0]=='C'){
            scanf("%d",&d);
            change(l,r,d);
        }
        else printf("%lld\n",ask(l,r));
    }
}

参考:https://blog.csdn.net/qq_39897867/article/details/82809676

线段树:


#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#define eps 0.00000001

using namespace std;

int num[400000];

struct node

{

    int l,r;

    long long nsum;

    long long add;

}seg[400000];

void Build(int i,int l,int r)

{

    seg[i].l=l;

    seg[i].r=r;

    seg[i].add=0;

    if(l==r)

    {

        seg[i].nsum=num[l];

        return ;

    }

    int mid=l+((r-l)>>1);

    Build(i<<1,l,mid);

    Build(i<<1|1,mid+1,r);

    seg[i].nsum=seg[i<<1].nsum+seg[i<<1|1].nsum;

}

void Add(int i,int l,int r,long long c)

{

    if(seg[i].l==l&&seg[i].r==r)

    {

        seg[i].add+=c;

        return ;

    }

    seg[i].nsum+=c*(r-l+1);

    int mid=(seg[i].l+seg[i].r)>>1;

    if(r<=mid) Add(i<<1,l,r,c);

    else if(l>mid) Add(i<<1|1,l,r,c);

    else

    {

        Add(i<<1,l,mid,c);

        Add(i<<1|1,mid+1,r,c);

    }

}

long long Query(int i,int a,int b)//查询a-b的总和

{

    if(seg[i].l==a&&seg[i].r==b)

    {

        return seg[i].nsum+(b-a+1)*seg[i].add;

    }

    seg[i].nsum+=(seg[i].r-seg[i].l+1)*seg[i].add;

    int mid=(seg[i].l+seg[i].r)>>1;

    Add(i<<1,seg[i].l,mid,seg[i].add);

    Add(i<<1|1,mid+1,seg[i].r,seg[i].add);

    seg[i].add=0;

    if(b<=mid)  return Query(i<<1,a,b);

    else if(a>mid)  return Query(i<<1|1,a,b);

    else return Query(i<<1,a,mid)+Query(i<<1|1,mid+1,b);

}

int main()

{

    int n,m,i;

    int a,b,c;

    char s[10];

    while(~scanf("%d%d",&n,&m))

    {

        for(i=1;i<=n;i++)

        {

            scanf("%d",&num[i]);

        }

        Build(1,1,n);

        for(i=0;i<m;i++)

        {

            scanf("%s",s);

            if(s[0]=='C')

            {

                scanf("%d%d%d",&a,&b,&c);

                Add(1,a,b,c);

            }

            else

            {

                scanf("%d%d",&a,&b);

                cout<<Query(1,a,b)<<endl;

            }

        }

    }

    return 0;

}

 参考:https://blog.csdn.net/bless924295/article/details/51569413

树状数组

#include<cstdio>
#include<algorithm>
#include<iostream>
#define lobit(x) x&-x
using namespace std;
long long t[2][100010],x,a[100010],sum[100010];
int n,m,l,r;
void add(int k,int x,int num)//修改
{
    while(x<=n)
    {
        t[k][x]+=num;
        x+=lobit(x);
    }
}
long long ask(int k,int x)//查询
{
    long long sum=0;
    while(x>0)
    {
        sum+=t[k][x];
        x-=lobit(x);
    }
    return sum;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<=m;i++)
    {
        char c[2];
        scanf("%s %d %d",c,&l,&r);
        if(c[0]=='Q')
        {
            long long ans=sum[r]+(r+1)*ask(0,r)-ask(1,r);
            ans-=sum[l-1]+l*ask(0,l-1)-ask(1,l-1);
            //查询
            printf("%lld\n",ans);
        }
        else
        {
            scanf("%d",&x);
            add(0,l,x);
            add(0,r+1,-x);
            add(1,l,l*x);
            add(1,r+1,-(r+1)*x);//修改
        }
    }
}

参考:https://blog.csdn.net/Mr_wuyongcong/article/details/81974566 

猜你喜欢

转载自blog.csdn.net/CYBCLOUD/article/details/88291145