区间问题
http://cdqz.openjudge.cn/noip/1020/
描述:
给你N个整数:A1, A2, ... , AN. 你需要处理两类操作。整个区间加上一个值,区间求和。
输入:
一个文件一组测试数据
第一行包括两个整数N,Q.0<N,Q<=100000.
第二行有N个整数A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
接下来有Q行,每行为以下两种形势之一
"C a b c"表示将将Aa, Aa+1, ... , Ab全体加上c. -10000 ≤ c ≤ 10000.
"Q a b"表示求Aa, Aa+1, ... , Ab的和。
输出:
对于每个Q命令,输出一行,表示求和结果。
样例输入:
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
样例输出:
4
55
9
15
时间限制:2000ms
题解:
线段树的模板题,支持两种最基本的操作。用到懒惰标记进行优化,在每次统计和增添的时候传递标记,更新节点的值即可。另外用到新学的位运算略微优化,据说这样会快一些。
心得:
初讲线段树的时候没听懂,然后晚上自己慢慢摸索,稍稍参考了一下钟神的代码,花了大约两个小时的时间写完,对于递归和树形结构的理解稍微加深了些。另外,据说考试的时候有30分的数据就是样例……
View Code
1 type 2 segtree=record 3 l,r:longint; 4 d,f:int64; 5 end; 6 var 7 a:array[1..1000000]of segtree; 8 m,n,i,j,k,data:longint; 9 c:char; 10 procedure update(p:longint); 11 begin 12 a[p].d:=a[p shl 1].d+a[(p shl 1)or 1].d; 13 end; 14 procedure build(left,right,rt:longint); 15 var 16 p:longint; 17 begin 18 a[rt].l:=left; 19 a[rt].r:=right; 20 if left=right then begin 21 read(a[rt].d); 22 a[rt].f:=0; 23 end 24 else begin 25 p:=(left+right)shr 1; 26 build(left,p,rt shl 1); 27 build(p+1,right,(rt shl 1)or 1); 28 update(rt); 29 end; 30 end; 31 procedure push(rt,left,right:longint); 32 var 33 q:longint; 34 begin 35 if a[rt].f<>0 then begin 36 inc(a[rt shl 1].f,a[rt].f); 37 inc(a[(rt shl 1)or 1].f,a[rt].f); 38 q:=(left+right)shr 1; 39 inc(a[rt shl 1].d,(q-left+1)*a[rt].f); 40 inc(a[(rt shl 1)or 1].d,(right-q)*a[rt].f); 41 a[rt].f:=0; 42 end; 43 end; 44 procedure plus(rt:longint); 45 var 46 q:longint; 47 begin 48 if (a[rt].l>=j)and(a[rt].r<=k) then begin 49 inc(a[rt].d,(a[rt].r-a[rt].l+1)*data); 50 inc(a[rt].f,data); 51 end else begin 52 push(rt,a[rt].l,a[rt].r); 53 q:=(a[rt].l+a[rt].r)shr 1; 54 if q>=j then plus(rt shl 1); 55 if q<k then plus((rt shl 1)or 1); 56 update(rt); 57 end; 58 end; 59 function find(rt:longint):int64; 60 var 61 q,p:longint; 62 begin 63 find:=0; 64 if (a[rt].l>=j)and(a[rt].r<=k) then begin 65 find:=a[rt].d; 66 end 67 else begin 68 push(rt,a[rt].l,a[rt].r); 69 q:=(a[rt].l+a[rt].r)shr 1; 70 if q>=j then inc(find,find(rt shl 1)); 71 if q<k then inc(find,find((rt shl 1)or 1)); 72 end; 73 end; 74 begin 75 read(n,m); 76 build(1,n,1); 77 readln; 78 for i:=1 to m do begin 79 read(c); 80 case c of 81 'C':begin 82 read(j,k); 83 readln(data); 84 plus(1); 85 end; 86 'Q':begin 87 read(j); 88 readln(k); 89 writeln(find(1)); 90 end; 91 end; 92 end; 93 end.