POJ3468 A Simple Problem with Integers

A Simple Problem with Integers
Time Limit: 5000MS   Memory Limit: 131072K
Total Submissions: 128968   Accepted: 40007
Case Time Limit: 2000MS

Description

You have N integers, A1A2, ... , 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 A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+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.

Source

POJ Monthly--2007.11.25, Yang Yi


解析:

    这道题可以用以下几种方法求解:

    1.树状数组 O((N+Q)logN)

    2.线段树 O((N+Q)logN)

    3.分块 O((N+Q)√N ̄

    4.朴素 ((N+Q)*N)

    在这里我着重说一下分块。

    我们可以把数列A分成长度不超过[√N]的段。设add[i]为第i段的增量标记,sum[i]表示第i段的和。

    对于操作 C l r d:

    1.如果l和r同时处于第i段,则直接把a[l]......a[r]都加上d,同时sum[i]+=d*(r-l+1)。

    2.如果l处于p段,r处于q段。那么对于i∈[p+1,q-1],令add[i]+=d。对于开头,结尾不足一整段的两部分,

按照第一种情况操作即可。

    对于询问 Q l r:

    1.如果l和r同时处于第i段,则ans=(a[l]+......+a[r])+add[i]*(r-l+1)。

    2.如果l处于p段,r处于q段。则对于i∈[p+1,q-1],令ans+=sum[i]+add[i]*len[i],其中len[i]表示第i段的长度。

对于开头结尾不足一段的两部分,按照第一种方法累加即可。

    总之,分块的基本思想可以被概括为:大段维护,局部朴素


代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;

const int Max=110010;
int n,q,m,tot;
long long sum[Max],add[Max],num[Max];
int L[Max],R[Max];
int father[Max];

inline void Add(int l,int r,long long val)
{
   int p=father[l],q=father[r];
   if(p==q)
   {
   	 for(int i=l;i<=r;i++) num[i]+=val;
   	 sum[p]+=(r-l+1)*val;
   }
   else
   {
   	 for(int i=p+1;i<=q-1;i++) add[i]+=val;
   	 for(int i=l;i<=R[p];i++) num[i]+=val;
   	 for(int i=L[q];i<=r;i++) num[i]+=val;
   	 sum[p]+=(R[p]-l+1)*val;sum[q]+=(r-L[q]+1)*val;
   }
}

inline long long ask(int l,int r)
{
   int p=father[l],q=father[r];
   long long ans=0;
   if(p==q)
   {
   	 for(int i=l;i<=r;i++) ans+=num[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+=num[i];
   	 for(int i=L[q];i<=r;i++) ans+=num[i];
   	 ans+=(R[p]-l+1)*add[p]+(r-L[q]+1)*add[q];
   }
   return ans;
}
int main()
{
     scanf("%d%d",&n,&q);
     for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
     scanf("\n");

     m=sqrt(n);
     for(int i=1;i<=m;i++)
     {
   	   L[i]=(i-1)*m+1;
   	   R[i]=i*m;
     }
     if(R[m]<n) {m++;L[m]=R[m-1]+1;R[m]=n;}

     for(int i=1;i<=m;i++)
       for(int j=L[i];j<=R[i];j++)
       {
         father[j]=i;
         sum[i]+=num[j];
       }

     while(q--)
     {
       int x,y;
   	   char c=getchar();
   	   scanf("%d%d",&x,&y);
   	   if(c=='Q') cout<<ask(x,y)<<"\n";
   	   else
   	   {
   	     int z;
   	     scanf("%d",&z);
   	     Add(x,y,z);
   	   }
   	   scanf("\n");
     }

     return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/80028337