A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 132802 Accepted: 41201
Case Time Limit: 2000MS
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
Hint
The sums may exceed the range of 32-bit integers.
题目大意思:
给定一个数列,有两种操作
1、(输入为Q)查询区间[l,r]数字总和
2、(输入为W)为区间[l,r]加上一个数num
解题思路:
1、用分块,将length为n数列分成根号n块,(最后一块可能会少)然后处理l,r两边各自的分块(朴素处理,也就是说是直接for),最后再直接处理中间分块的。
sum:每一个分块的总合
orz:记录数列
add:中间那一部分可以整个分块整体都要加的加的
时间复杂度:O((N+Q)logN)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200005
using namespace std;
long long add[N];
long long orz[N];
long long sum[N];
char s;
long long l,r;
long m,g,p;
long long num;
long long ans;
int find(long long g)
{
if(g%num>=1)
g=g/num+1;
else
g=g/num;
return g;
}
void lookup(long long l,long long r)
{
long long x=find(l);//查找左侧l位于哪个区间
long long y=find(r);//同理,查找右侧r位于哪个区间
if(y-x<=1)//判断l,r是否在相邻或同一个区间,若是直接朴素for过去,更快
{
for(int i=l;i<=r;i++)
ans+=orz[i]+add[find(i)];
}
else
{
for(int i=l;i<=num*x;i++)
ans=ans+orz[i]+add[x];
for(int i=r;i>=num*(y-1)+1;i--)
ans=ans+orz[i]+add[y];
for(int i=x+1;i<=y-1;i++)
ans=ans+sum[i]+num*add[i];
}
printf("%lld\n",ans);
// for(int i=1;i<=m;i++)printf("%d ",orz[i]);
// printf("\n");
// for(int i=1;i<=sqrt(m)+1;i++)printf("%d ",sum[i]);
// printf("\n");
// for(int i=1;i<=sqrt(m)+1;i++)printf("%d ",add[i]);
// printf("\n");
ans=0;
}
void insert(long long l,long long r,long long www)
{
int x=find(l);
int y=find(r);
long long xl=0;
if (num*x>m) xl=m;
else xl=num*x;//特判处理左边节点是的区间最右的成员(因为有可能是在最后一个不完全区间)
if(x==y)xl=r;
for(int i=l;i<=xl;i++)
{
orz[i]+=www;
sum[x]+=www;
}
if(x!=y) //判断是否了l,r在同一个区间,防止多加
{
for(int i=r;i>=num*(y-1)+1;i--)
{
orz[i]+=www;
sum[y]+=www;
}
}
for(int i=x+1;i<=y-1;i++)
add[i]+=www;
}
int main()
{
//freopen("a.out","w",stdout);
scanf("%lld %lld",&m,&p);
for(int i=1;i<=m;i++)
scanf("%lld",&orz[i]);
num=sqrt((double)m);//取根号m的整数
int j=1;
for(int i=1;i<=m/num;i++)
{
int k=1;
while(k<=num)
{
sum[i]+=orz[j];
j++;
k++;
}
}
for(int i=j;i<=m;i++)sum[m/num+1]+=orz[i];
long long t=0;
long long ss=0;
long long ber=0;
for(int i=1;i<=p;i++)
{
cin>>s;
switch(s)
{
case 'Q':scanf("%lld %lld",&t,&ss);
lookup(t,ss);
break;
case 'C':scanf("%lld %lld %lld",&t,&ss,&ber);
insert(t,ss,ber);
break;
}
}
return 0;
}