POJ 3468 线段树裸题

  这些天一直在看线段树,因为临近期末,所以看得断断续续,弄得有些知识点没能理解得很透切,但我也知道不能钻牛角尖,所以配合着刷题来加深理解。

  然后,这是线段树裸题,而且是最简单的区间增加与查询,我参考了ACdreamer的模板,在此基础上自己用宏定义来精简了一下代码:

 1 #include<cstdio>
 2 typedef long long LL;
 3 #define root  int rt, int l, int r
 4 #define lson  rt*2, l, mid
 5 #define rson  rt*2+1, mid+1, r
 6 #define makemid  int mid= (l+r)>>1
 7 int a,b;
 8 LL c;
 9
10 struct tree {
11     LL add,sum;
12 } s[400003];
13
14 void build(root) {
15     s[rt].add= 0;
16     if(l==r){
17         scanf("%lld",&s[rt].sum);
18         return ;
19     }
20     makemid ;
21     build(lson);
22     build(rson);
23     s[rt].sum= s[rt*2].sum+s[rt*2+1].sum;
24 }
25
26 inline void pushdown(int rt, int len) {
27     int ls= rt*2, rs= ls+1;
28     const LL &c= s[rt].add;
29     s[ls].add += c;
30     s[rs].add += c;
31     s[ls].sum += c*(len-len/2);
32     s[rs].sum += c*(len/2);
33     s[rt].add= 0;
34 }
35
36 void update(root) {
37     if(a<=l && r<=b){
38         s[rt].add+= c;
39         s[rt].sum+= c*(r-l+1);
40         return ;
41     }
42     if(s[rt].add)    pushdown(rt,r-l+1);
43     makemid ;
44     if(a<=mid)    update(lson);
45     if(b>mid)    update(rson);
46     s[rt].sum= s[rt*2].sum+s[rt*2+1].sum;
47 }
48
49 LL query(root) {
50     if(a<=l && r<=b)    return s[rt].sum;
51     if(s[rt].add)    pushdown(rt,r-l+1);
52     makemid ;
53     LL res= 0;
54     if(a<=mid)    res+= query(lson);
55     if(b>mid)    res+= query(rson);
56     return res;
57 }
58
59 int main(){
60     int n,q;
61     while(~scanf("%d%d",&n,&q)){
62         build(1,1,n);
63         while(q--){
64             getchar();
65             if(getchar()==‘Q‘){
66                 scanf("%d%d",&a,&b);
67                 printf("%lld\n",query(1,1,n));
68             }
69             else {
70                 scanf("%d%d%lld",&a,&b,&c);
71                 update(1,1,n);
72             }
73         }
74     }
75     return 0;
76 }

  原样的代码是:

 1 #include<cstdio>
 2 typedef long long LL;
 3 LL c;
 4 int a,b;
 5
 6 struct tree{
 7     LL add,sum;
 8 } s[400003];
 9
10 void build(int rt, int l, int r){
11     s[rt].add= 0;
12     if(l==r){
13         scanf("%lld",&s[rt].sum);
14         return ;
15     }
16     int mid= (l+r)>>1;
17     build(rt*2,l,mid);
18     build(rt*2+1,mid+1,r);
19     s[rt].sum= s[rt*2].sum+s[rt*2+1].sum;
20 }
21
22 inline void pushdown(int rt, int len){
23     if(s[rt].add){
24         int ls= rt*2, rs= ls+1;
25         s[ls].add += s[rt].add;
26         s[rs].add += s[rt].add;
27         s[ls].sum += s[rt].add*(len-len/2);
28         s[rs].sum += s[rt].add*(len/2);
29         s[rt].add= 0;
30     }
31 }
32
33 void update(int rt, int l, int r){
34     if(a<=l && r<=b){
35         s[rt].add+= c;
36         s[rt].sum+= c*(r-l+1);
37         return ;
38     }
39     pushdown(rt,r-l+1);
40     int mid= (l+r)>>1;
41     if(a<=mid)    update(rt*2,l,mid);
42     if(b>mid)    update(rt*2+1,mid+1,r);
43     s[rt].sum= s[rt*2].sum+s[rt*2+1].sum;
44 }
45
46 LL query(int rt, int l, int r){
47     if(a<=l && r<=b)    return s[rt].sum;
48     pushdown(rt,r-l+1);
49     int mid= (l+r)>>1;
50     LL res= 0;
51     if(a<=mid)    res+= query(rt*2,l,mid);
52     if(b>mid)    res+= query(rt*2+1,mid+1,r);
53     return res;
54 }
55
56 int main(){
57     int n,q;
58     while(~scanf("%d%d",&n,&q)){
59         build(1,1,n);
60         while(q--){
61             getchar();
62             if(getchar()==‘Q‘){
63                 scanf("%d%d",&a,&b);
64                 printf("%lld\n",query(1,1,n));
65             }
66             else {
67                 scanf("%d%d%lld",&a,&b,&c);
68                 update(1,1,n);
69             }
70         }
71     }
72     return 0;
73 }

  线段树,不断进取中~~

时间: 2024-10-18 07:51:07

POJ 3468 线段树裸题的相关文章

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4027 Can you answer these queries? 线段树裸题

题意: 给定2个操作 0.把区间的每个数sqrt 2.求和 因为每个数的sqrt次数很少,所以直接更新到底,用个标记表示是否更新完全(即区间内的数字只有0,1就不用再更新了) #include<stdio.h> #include<iostream> #include<algorithm> #include<vector> #include<cmath> #include<queue> #include<set> #incl

POJ 3468 线段树+lazy标记

lazy标记 Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u Submit Status 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

poj 3468 线段树成段更新

http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58132   Accepted: 17704 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two k

POJ 3468 线段树(成段更新,区间求和)

题目链接:http://poj.org/problem?id=3468 题意:给定一个数列,每次操作可以是将某区间数字都加上一个相同的整数,也可以是询问一个区间中所有数字的和,对每次询问输出结果. 这个线段树运用了应用了add域优化,每个节点除了用value记录当前节点对应区间元素的和之外,还要用add域记录当前节点对应区间每个元素的增量.这样,没必要每次更新都要更新value更新到最底层每一个点,只需要将增量记录在某父节点的add域中即可,如果下次查询或者更新操作的是该父节点对应区间的子区间,

bzoj 1036 树链剖分+线段树 裸题

HYSBZ - 1036 题意:中文题 思路:树链剖分裸题,线段树写得比较搓,(在线段树上修改节点u的时候应该修改u映射到线段树后的节点序号,这里wa了半年,真的是半年) AC代码: #include "iostream" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector

hdu 1698+poj 3468 (线段树 区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1698 这个题意翻译起来有点猥琐啊,还是和谐一点吧 和涂颜色差不多,区间初始都为1,然后操作都是将x到y改为z,注意 是改为z,不是加或减,最后输出区间总值 也是线段树加lazy操作 1 #include<cstdio> 2 using namespace std; 3 struct point { 4 int l,r; 5 int val,sum; 6 }; 7 point tree[400007]; 8

CPU监控 线段树裸题

LINK:bzoj3064 此题甚好码了20min停下来思考的时候才发现不对的地方有点坑... 还真不好写来着 可这的确是线段树的裸题...我觉得我写应该没有什么大问题 不过思路非常的紊乱 如果是自己写的话 所以为了自己能写出来 整理思路就是这篇博客了. Q X Y:询问从X到Y这段时间内CPU最高使用率 A X Y:询问从X到Y这段时间内之前列出的事件使CPU达到过的最高使用率 P X Y Z:列出一个事件这个事件使得从X到Y这段时间内CPU使用率增加Z C X Y Z:列出一个事件这个事件使

Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)

题目链接 题意:开始有一个空白的区间,每次可能进行两个操作:A 将一个长度为p的区间加入一段连续空白的位置 L:一个区间恢复空白:要求出A不能进行的次数. 非常裸的线段树题目,用线段树统计最大的空白区间,每个节点需要记录当前区间的最长空白区间,从左端开始的最长空白区间,从右端开始的最长空白区间.Push_up的时候要讨论下,可以分别取[l,mid]和[mid+1,r]的最大空白区间,也可以用[l,mid]的从右端开始的最长空白区间+[mid+1,r]从左端开始的最大空白区间. 每次A的时候,就查