POJ:3468
从下午开始做,一直做到晚上八点。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; }