从下午开始做,一直做到晚上八点。ACM新手,刚接触线段树。
题意很简单,Q代表查寻一段区间内Ai的和,C表示往区间内增加。
这题如果直接老方法,就是更新到结点,查询到区间的话,,,很容易就超时,
struct SegTree{
int left,right;
long long count , add ;
}st[MAX];
所以为做这道题得学新东西。对线段树中的更新操作中有一种算法叫延迟标记,也就是lazy算法。
算法的思想是在原来的结构体中增加一个add域,每次更新时只更新到一个大区间,并把add增加(具体增加多少看题目)。
在每次访问的时候需要把这个区间的add给往下推,这时候不要忘了对count更新,count=add*(right-left+1);
下面是代码:
/*
A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 66090 Accepted: 20346
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.
*/
#include <stdio.h>
#define MAX 400000
struct SegTree{
int left,right;
long long count , add ;
}st[MAX];
void creatTree(int left , int right , int pos)
{
st[pos].count = 0;
st[pos].add = 0 ;
st[pos].left = left ;
st[pos].right = right ;
if(left == right)
{
return ;
}
int mid = (left + right)>>1;
creatTree(left , mid , pos<<1) ;
creatTree(mid+1 , right , pos<<1|1);
}
void init(int x , int data , int pos)
{
st[pos].count += data ;
if(st[pos].left == st[pos].right && st[pos].left == x)
{
return ;
}
int mid = (st[pos].left + st[pos].right)>>1;
if(x > mid)
{
init(x,data,pos<<1|1);
}
else
{
init(x,data,pos<<1);
}
}
void update(int left , int right , int data , int pos)
{
if(left == st[pos].left && right == st[pos].right) //更新到区间,add增加
{
st[pos].add += data ;
return ;
}
st[pos].count += data*(right-left+1) ; //如果要查询的区间小于大的区间的话,更新大区间的count;
int mid = (st[pos].left + st[pos].right)>>1;
if(left > mid)
{
update(left , right , data ,pos<<1|1);
}
else if(right <= mid)
{
update(left , right , data , pos<<1);
}
else
{
update(left , mid , data , pos<<1);
update(mid+1,right , data ,pos<<1|1);
}
}
long long query(int left ,int right , int pos)
{
long long sum = 0 ;
if(st[pos].left == left && st[pos].right == right)
{
return st[pos].count + st[pos].add*(st[pos].right - st[pos].left + 1);
}
int p = pos<<1 ;
if(st[pos].add && p+1 < MAX) //查询的时候,把add往下推
{
st[p].add += st[pos].add;
st[p+1].add += st[pos].add;
st[pos].count += st[pos].add*(st[pos].right - st[pos].left + 1) ; //父节点的count需要更新
st[pos].add = 0 ;
}
int mid = (st[pos].left + st[pos].right)>>1;
if(left > mid)
{
sum += query(left , right , pos<<1|1);
}
else if(right <= mid)
{
sum += query(left , right , pos<<1);
}
else
{
sum += query(left , mid , pos<<1);
sum += query(mid+1,right , pos<<1|1);
}
return sum ;
}
int main()
{
int n,q;
while(scanf("%d%d",&n,&q) != EOF)
{
char ch;
int l,r;
long long data;
creatTree(1,n,1);
for(int i = 0 ; i < n ; ++i)
{
scanf("%lld",&data);
init(i+1 , data , 1);
}
for(int i = 0 ; i < q ; ++i)
{
while(scanf("%c",&ch))
{
if(ch != ' ' && ch != '\n')
break;
}
if(ch == 'Q')
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(l,r,1));
}
else
{
scanf("%d%d%lld",&l,&r,&data);
update(l,r,data,1);
}
}
}
return 0;
}