Time Limit: 5000MS | Memory Limit: 131072K | |
Total Submissions: 81443 | Accepted: 25160 | |
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
题意:给出一个含有n个整数的数列,C a b c表示在数列中从第a个元素到第b个元素值都增加c,Q a b表示从第a个数到第b个数相加,并输出所得值。
题解:很明显的区间求和问题,用线段树解,不能一次只更新区间内一个点,明显会超时,可以给每个节点加一个temp量来记录增量的累加。QAQ,根本不懂,倒腾了两天,最后照着匡斌的代码才A的。线段树必须重看
代码如下:
#include<cstdio>
int a[100000+100];
struct node
{
int left,right;
__int64 temp;
__int64 sum;
}num[400010];
__int64 build(int left,int right,int cnt)
{
int mid;
num[cnt].left=left;
num[cnt].right=right;
num[cnt].temp=0;
num[cnt].sum=0;
if(left==right)
return num[cnt].sum=a[left];
mid=(left+right)>>1;
return num[cnt].sum=build(left,mid,cnt*2)+build(mid+1,right,cnt*2+1);
}
void update(int left,int right,__int64 count,int cnt)
{
int mid;
if(left==num[cnt].left&&right==num[cnt].right)
{
num[cnt].temp+=count;
return ;
}
num[cnt].sum+=count*(right-left+1);
mid=(num[cnt].left+num[cnt].right)>>1;
if(right<=mid)
update(left,right,count,cnt*2);
else if(left>mid)
update(left,right,count,cnt*2+1);
else
{
update(left,mid,count,cnt*2);
update(mid+1,right,count,cnt*2+1);
}
}
__int64 query(int left,int right,int cnt)
{
int mid;
if(left==num[cnt].left&&num[cnt].right==right)
return num[cnt].sum+(right-left+1)*num[cnt].temp;
mid=(num[cnt].left+num[cnt].right)>>1;
num[cnt].sum+=(num[cnt].right-num[cnt].left+1)*num[cnt].temp;
update(num[cnt].left,mid,num[cnt].temp,cnt*2);
update(mid+1,num[cnt].right,num[cnt].temp,cnt*2+1);
num[cnt].temp=0;
if(right<=mid)
return query(left,right,cnt*2);
else if(left>mid)
return query(left,right,cnt*2+1);
else
return query(left,mid,cnt*2)+query(mid+1,right,cnt*2+1);
}
int main()
{
int N,Q,n,m,i,count;
char s[2];
while(scanf("%d%d",&N,&Q)!=EOF)
{
for(i=1;i<=N;i++)
scanf("%d",&a[i]);
build(1,N,1);
while(Q--)
{
scanf("%s",s);
if(s[0]=='C')
{
scanf("%d%d%d",&n,&m,&count);
update(n,m,count,1);
}
else
{
scanf("%d%d",&n,&m);
printf("%I64d\n",query(n,m,1));
}
}
}
return 0;
}
2016/3/22更新:
成段更新要用到懒惰标记(lazy思想,延迟更新)。之前一直没认真看lazy思想,今天找到一篇不错的博文讲述Lazy思想: Lazy思想
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 100010
#define LL long long
#define lson i*2,l,m
#define rson i*2+1,m+1,r
LL sum[maxn*4];
LL addv[maxn*4];
void PushDown(int i,int num)
{
if(addv[i])
{
sum[i*2]+=addv[i]*(num-(num/2));
sum[i*2+1]+=addv[i]*(num/2);
addv[i*2]+=addv[i];
addv[i*2+1]+=addv[i];
addv[i]=0;
}
}
void PushUp(int i)
{
sum[i]=sum[i*2+1]+sum[i*2];
}
void build(int i,int l,int r)
{
addv[i]=0;
if(l==r)
{
scanf("%I64d",&sum[i]);
return ;
}
int m=(l+r)/2;
build(lson);
build(rson);
PushUp(i);
}
void update(int ql,int qr,int add,int i,int l,int r)
{
if(ql<=l&&r<=qr)
{
addv[i]+=add;
sum[i]+=(LL)add*(r-l+1);
return ;
}
PushDown(i,r-l+1);
int m=(l+r)/2;
if(ql<=m)
update(ql,qr,add,lson);
if(qr>m)
update(ql,qr,add,rson);
PushUp(i);
}
LL query(int ql,int qr,int i,int l,int r)
{
if(ql<=l&&r<=qr)
return sum[i];
PushDown(i,r-l+1);
int m=(l+r)/2;
LL ans=0;
if(ql<=m)
ans+=query(ql,qr,lson);
if(m<qr)
ans+=query(ql,qr,rson);
return ans;
}
int main()
{
int n,q,x,y,z;
char s[5];
while(scanf("%d%d",&n,&q)!=EOF)
{
build(1,1,n);
while(q--)
{
scanf("%s",s);
if(s[0]=='C')
{
scanf("%d%d%d",&x,&y,&z);
update(x,y,z,1,1,n);
}
else
{
scanf("%d%d",&x,&y);
printf("%I64d\n",query(x,y,1,1,n));
}
}
}
return 0;
}
树状数组解法:
#include<cstdio>
#include<cstring>
#define maxn 100010
#define LL long long
LL bit1[maxn],bit2[maxn];
int n,q;
LL sum(LL *b, int i)
{
LL ans = 0;
while(i > 0)
{
ans += b[i];
i -= i & -i;
}
return ans;
}
void add(LL *b, int i, int x)
{
while(i <= n)
{
b[i] += x;
i += i & -i;
}
}
int main()
{
int x, y, i;
LL a, z;
char s[5];
while(scanf("%d%d",&n,&q)!=EOF)
{
for(i = 1; i <= n; ++i)
{
scanf("%I64d",&a);
add(bit1, i, a);
}
while(q--)
{
scanf("%s",s);
if(s[0] == 'C')
{
scanf("%d%d%I64d",&x, &y, &z);
add(bit1, x, -z * (x - 1) );
add(bit2, x, z);
add(bit1, y + 1, z * y);
add(bit2, y + 1, -z);
}
else
{
scanf("%d%d",&x, &y);
LL ans = 0;
ans += sum(bit1, y) + sum(bit2, y) * y;
ans -= sum(bit1, x-1) + sum(bit2, x-1) * (x - 1);
printf("%I64d\n",ans);
}
}
}
return 0;
}