线段树_POJ-3468

题目链接:http://poj.org/problem?id=3468

线段树裸题。。。。

用了两种方法写:

1.lazy,效率略低

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define lowbit(a) ((a)&(-a))
 7 #define max(a, b) ((a)>(b)?(a):(b))
 8 #define min(a, b) ((a)<(b)?(a):(b))
 9 #define MAXN 100100
10 #define PI 3.1415926
11 #define E 2.718281828
12 #define INF 0x777777f
13 typedef long long LL;
14
15 struct tnode{
16     int lc, rc, l, r; LL data, tag;
17     void clear(){data = tag = lc = rc = 0;}
18 } tree[MAXN*4];
19 int n, m, tCnt; int a[MAXN];
20
21 /*根据儿子的信息更新*/
22 inline void update(tnode &p){
23     p.data = tree[p.lc].data + tree[p.rc].data;
24 }
25 /*根据父亲的tag更新(注意tag类型)*/
26 inline void update(tnode &p, LL tag){
27     p.data += (p.r-p.l+1)*tag;
28 }
29 /*下传tag信息*/
30 inline void pushdown(tnode &p){
31     if (!p.tag) return; if (p.l == p.r){p.tag = 0; return;}
32     int mid = (p.l+p.r)>>1;
33     if (p.lc) {tree[p.lc].tag += p.tag; update(tree[p.lc], p.tag);}
34     if (p.rc) {tree[p.rc].tag += p.tag; update(tree[p.rc], p.tag);}
35     p.tag = 0;
36 }
37 /*建树*/
38 void build(tnode &p, int l, int r){
39     p.l = l; p.r = r;
40     if (l == r) {p.data = a[l]; return;}
41     int mid = (l+r)>>1;
42     p.lc = ++tCnt; build(tree[p.lc], l, mid);
43     p.rc = ++tCnt; build(tree[p.rc], mid+1, r);
44     update(p);
45 }
46 /*修改*/
47 void change(tnode &p, int l, int r, int x){
48     pushdown(p);
49     if (l<=p.l && p.r<=r){p.tag = x; update(p, x); return;}
50     int mid = (p.l+p.r)>>1;
51     if (l <= mid) change(tree[p.lc], l, r, x);
52     if (mid  < r) change(tree[p.rc], l, r, x);
53     update(p);
54 }
55 /*查询(注意返回类型)*/
56 LL query(tnode &p, int l, int r){
57     pushdown(p);
58     if (l<=p.l && p.r<=r) {return p.data;}
59     int mid = (p.l+p.r)>>1; LL ret = 0;
60     if (l <= mid) ret += query(tree[p.lc], l, r);
61     if (mid  < r) ret += query(tree[p.rc], l, r);
62     return ret;
63 }
64 int main(){
65     scanf("%d%d", &n, &m);
66     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
67     tCnt = 1; build(tree[1], 1, n);
68     char c = getchar(); int l, r, x;
69     for (int i = 1; i <= m; i++){
70         c = getchar();
71         if (c==‘C‘){
72             scanf("%d%d%d", &l, &r, &x);
73             change(tree[1], l, r, x);
74         }
75         else {
76             scanf("%d%d", &l, &r);
77             printf("%I64d\n", query(tree[1], l, r));
78         }
79         getchar();
80     }
81     return 0;
82 }

2.标记永久化,效率较高

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 #define lowbit(a) ((a)&(-a))
 7 #define max(a, b) ((a)>(b)?(a):(b))
 8 #define min(a, b) ((a)<(b)?(a):(b))
 9 #define MAXN 100100
10 #define PI 3.1415926
11 #define E 2.718281828
12 #define INF 0x777777f
13 typedef long long LL;
14
15 struct tnode{
16     int lc, rc, l, r; LL data, tag;
17     void clear(){data = tag = lc = rc = 0;}
18 } tree[MAXN*4];
19 int n, m, tCnt; int a[MAXN];
20
21 /*建树*/
22 void build(tnode &p, int l, int r){
23     p.l = l; p.r = r;
24     if (l == r) {p.data = a[l]; return;}
25     int mid = (l+r)>>1;
26     p.lc = ++tCnt; build(tree[p.lc], l, mid);
27     p.rc = ++tCnt; build(tree[p.rc], mid+1, r);
28     /*update_p*/
29         p.data = tree[p.lc].data+tree[p.rc].data;
30     /*update_p*/
31 }
32 /*修改(l、r都在p的范围内)*/
33 void change(tnode &p, int l, int r, int v){
34     /*update_p*/
35         p.data += (r-l+1)*v;
36         if (l==p.l && p.r==r) {p.tag += v; return;}
37     /*update_p*/
38     int mid = (p.l+p.r)>>1;
39     if (r <= mid) {change(tree[p.lc], l, r, v); return;}            //全在左子树
40     if (l >  mid) {change(tree[p.rc], l, r, v); return;}            //全在右子树
41     change(tree[p.lc], l, mid, v); change(tree[p.rc], mid+1, r, v);    //越过中点
42 }
43 /*查询(注意返回类型,其他同上)*/
44 LL query(tnode &p, int l, int r){
45     if (l==p.l && p.r==r) {return p.data;}
46     int mid = (p.l+p.r)>>1; LL ret = (r-l+1)*p.tag;
47     if (r <= mid) return ret+query(tree[p.lc], l, r);
48     if (l >  mid) return ret+query(tree[p.rc], l, r);
49     return ret+query(tree[p.lc], l, mid)+query(tree[p.rc], mid+1, r);
50 }
51 int main(){
52     scanf("%d%d", &n, &m);
53     for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
54     tCnt = 1; build(tree[1], 1, n);
55     char c = getchar(); int l, r, x;
56     for (int i = 1; i <= m; i++){
57         c = getchar();
58         if (c==‘C‘){
59             scanf("%d%d%d", &l, &r, &x);
60             change(tree[1], l, r, x);
61         }
62         else {
63             scanf("%d%d", &l, &r);
64             printf("%I64d\n", query(tree[1], l, r));
65         }
66         getchar();
67     }
68     return 0;
69 }
时间: 2024-08-02 10:09:52

线段树_POJ-3468的相关文章

线段树 POJ 3468

这周学习了一下线段树,偶遇POJ 3468,这道题是线段树区间更新,题意大概是有一段的长为n的数组,经过若干次对其中某一段的数进行加减,询问某一段的和.这题还是比较明显的线段树,如果细分到对每一个节点进行操作的话,复杂度为O(m^logn),容易超时,所以采取延迟标记的做法,直接对某一段进行操作,而暂不对其子树进行操作,话不多说,直接上代码吧 #include<cstdio> #include<cstring> #include<cstdlib> #include &l

线段树 POJ 3468 A Simple Problem with Integers

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. In

poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)

题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 83959   Accepted: 25989 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. Yo

POJ 3468 A Simple Problem with Integers(线段树)

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

poj 3468 A Simple Problem with Integers(原来是一道简单的线段树区间修改用来练练splay)

题目链接:http://poj.org/problem?id=3468 题解:splay功能比线段树强大当然代价就是有些操作比线段树慢,这题用splay实现的比线段树慢上一倍.线段树用lazy标记差不多要2s用splay要4s.可以用splay来实现线段树的区间操作更深层次的了解一下splay算是入个门. #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #i

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

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

poj 3468 A Simple Problem with Integers (线段树成段更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 77486   Accepted: 23862 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

poj 3468 A Simple Problem with Integers 树状数组 或 线段树

题目链接:http://poj.org/problem?id=3468 一般说来 树状数组是 [单点更新 区间查询] 而本题是“区间更新 区间查询” 所以要改成维护前缀和 推公式的过程见<挑战程序设计竞赛>第181~182面 代码中bit0是i的零次项 bit1是i的一次项 以后以此类推 在[l, r]加数的时候 写出公式 在l的地方 一次项及以上的直接写 然后在零次项那减去 在r的地方 一次项及以上的减掉之前加上的 然后再零次项那加上“公式化简之后的最终结果 减去 之前在零次项加的那一项”

poj 3468 A Simple Problem with Integers 【线段树-成段更新】

题目:poj 3468 A Simple Problem with Integers 题意:给出n个数,两种操作 1:l -- r 上的所有值加一个值val 2:求l---r 区间上的和 分析:线段树成段更新,成段求和 树中的每个点设两个变量sum 和 num ,分别保存区间 l--r 的和 和l---r 每个值要加的值 对于更新操作:对于要更新到的区间上面的区间,直接进行操作 加上 (r - l +1)* val .下面的区间标记num += val 对于求和操作,每次进行延迟更新,把num值

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac