区间问题

区间问题

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.

 

转载于:https://www.cnblogs.com/wangziyun/archive/2012/07/09/2582114.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值