POJ3468 A Simple Problem with Integers(线段树延时标记)

题目地址http://poj.org/problem?id=3468

题目大意很简单,有两个操作,一个

Q a, b 查询区间[a, b]的和

C a, b, c让区间[a, b] 的每一个数+c

 

第一次线段树的延时标记,花了好大的功夫才写好==!

很容易看出来使用使用线段树记录区间的和,但是难点在于每次修改的是一个区间而不是一个点

所以采用的方法就是每次做修改操作时,只将区间[a,b]的标记+c,而不是真正意义上的将区间[a, b] 的每一个值+c。

而当我们做查询操作时,就只需要将区间[a, b]在从[1, N]开始查找到查找到时所经过的区间的标记往下传递就可以了(同时记得更新当前节点的值)

 

 1 #include <map>
 2 #include <set>
 3 #include <stack>
 4 #include <queue>
 5 #include <cmath>
 6 #include <ctime>
 7 #include <vector>
 8 #include <cstdio>
 9 #include <cctype>
10 #include <cstring>
11 #include <cstdlib>
12 #include <iostream>
13 #include <algorithm>
14 using namespace std;
15 #define INF 0x3f3f3f3f
16 #define mem0(a) memset(a,0,sizeof(a))
17 #define mem1(a) memset(a,-1,sizeof(a))
18 #define lson k<<1, L, mid
19 #define rson k<<1|1, mid+1, R
20 
21 typedef long long LL;
22 const double eps = 1e-12;
23 const int MAXN = 100005;
24 const int MAXM = 500005;
25 
26 struct Node { LL sum, add; } tree[MAXN<<2];
27 int a, b, N, Q;
28 LL c;
29 
30 void updataChild(int k, int L, int R)//将编号为k的标记传到他的子节点去
31 {
32     tree[k].sum += (R-L+1) * tree[k].add;//先更新它自己的sum值
33     tree[k<<1].add += tree[k].add;//将左右子节点的add值更新
34     tree[k<<1|1].add += tree[k].add;
35     tree[k].add = 0;//去掉标记
36 }
37 
38 void update(int k, int L, int R)//更新区间的值
39 {
40     if(R<a || b<L) return ;//不再区间内
41 
42     if(a<=L && R<=b) { tree[k].add += c;  return; }//实际上只更新这个区间的add值
43 
44     int mid = (L+R)>>1;     update(lson);      update(rson); //往左和往右更新
45 
46     tree[k].sum = tree[k<<1].sum + tree[(k<<1)+1].sum//更新当前节点的sum
47                   + (mid-L+1)*tree[k<<1].add + (R-mid)*tree[k<<1|1].add;
48 }
49 
50 LL query(int k, int L, int R)
51 {
52     if(R<a || b<L) return 0;
53 
54     if(a<=L && R<=b) return tree[k].sum + (R-L+1)*tree[k].add;//注意加上当前节点的标记
55 
56     int mid = (L+R)>>1;  updataChild(k, L, R);//吧标记传到子节点
57 
58     return query(lson) + query(rson);
59 }
60 
61 int main()
62 {
63     while(~scanf("%d %d", &N, &Q))
64     {
65         mem0(tree); char ch;
66         for(a=1;a<=N;a++)
67         {
68             scanf("%lld%*c", &c);  b = a;//区间是[a, a]
69             update(1, 1, N);
70         }
71         for(int i=0;i<Q;i++)
72         {
73             scanf("%c", &ch);
74             if(ch == 'Q')
75             {
76                 scanf("%d %d%*c", &a, &b);
77                 printf("%lld\n", query(1,1,N));
78             }
79             else
80             {
81                 scanf("%d %d %lld%*c", &a, &b, &c);
82                 update(1,1,N);
83             }
84         }
85     }
86     return 0;
87 }

 

转载于:https://www.cnblogs.com/gj-Acit/p/3574008.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值