线段树summer_work

写了几道题,对线段树的概念有了一定的认识,这里总结下我写的习惯,方便以后完善及复习。

线段树所用的函数:

  1. pushup():向上更新父节点
  2. build(): 与普通建树方式相同,最后要pushup()(向上更新(父节点的值)
  3. update():判断当前区间与给定区间的关系;若是点:找到点更新即可,若是区间:更新到rt即可,只有用到rt子节点,才向下更新。递归向下结束后,在向上的过程中更新父节点。
  4. query(): 判断当前rt与给定区间的关系,若用到lazy操作,查询时用到rt子节点则向下更新,递归过程中查询所需的内容
  5. putdown():配合lazy操作,向下更新结点。这里需要明白一段区间 [l, r]的 左儿子[l, (l+r)/2],右儿子[(l+r)/2+1, r],由此知左右子区间长度与父节点的区间长度的关系。(1)、关于pushdown()的部分更新感想见G题。

因为初学线段树,理解有限,这个总结我想一直完善下去。

A - 敌兵布阵

单点更新,查询区间和。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 #define LL long long
 7 #define lson l,m,rt<<1
 8 #define rson m+1,r,rt<<1|1
 9 #define midf(a,b) (((a) + (b))>>1)
10 const int maxnode = 50010;
11 struct Node{
12     int value;
13     int left, right;
14 }node[maxnode<<2];
15 void pushup(int rt){
16     node[rt].value = node[rt<<1].value+node[rt<<1|1].value;
17 }
18 void build(int l ,int r, int rt){
19     node[rt].left=l, node[rt].right=r, node[rt].value=0;
20     if(l == r){
21         scanf("%d", &node[rt].value);
22         return;
23     }
24     int m = midf(l, r);
25     build(lson);
26     build(rson);
27     pushup(rt);
28 }
29 //单点修改
30 void update(int a, int rt, int ans){
31     if(node[rt].left==a && node[rt].right==a){
32         node[rt].value += ans;
33         return;
34     }else{
35         int m = midf(node[rt].left, node[rt].right);
36         if(a <= m) update(a,rt<<1,ans);
37         if(a > m)  update(a,rt<<1|1, ans);
38         pushup(rt);  //向下找叶子结点军营的过程中,在每层需向上更新
39     }
40 }
41 //区间查询
42 LL query(int l, int r, int rt){
43     if(node[rt].left>=l && node[rt].right<=r){
44         return node[rt].value;
45     }
46     LL ans = 0;
47     int m = midf(node[rt].left, node[rt].right);
48     if(l <= m) ans += query(l,r,rt<<1);
49     if(r > m)  ans += query(l,r,rt<<1|1);  //找右儿子结点
50     return ans;
51 }
52 int main(){
53 //    freopen("in.txt", "r", stdin);
54     int tt;
55     scanf("%d",&tt);
56     for(int ttt=1; ttt<=tt; ttt++){
57         printf("Case %d:\n", ttt);
58         int n;
59         scanf("%d", &n);
60         build(1, n, 1);
61         char ask[10];
62         while(scanf("%s", ask) != EOF){
63             if(ask[0] == ‘E‘){
64                 break;
65             }else if(ask[0] == ‘A‘){
66                 int l, c;
67                 scanf("%d%d", &l, &c);
68                 update(l, 1, c);
69             }else if(ask[0] == ‘S‘){
70                 int l, c;
71                 scanf("%d%d", &l, &c);
72                 update(l, 1, -c);
73             }else{
74                 int l, r;
75                 scanf("%d%d", &l, &r);
76                 printf("%lld\n", query(l, r, 1));
77             }
78         }
79     }
80     return 0;
81 }

B - I Hate It

单点更新,查询区间最大值

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 #define LL long long
 7 #define lson l,m,rt<<1
 8 #define rson m+1,r,rt<<1|1
 9 #define midf(a,b) (((a) + (b))>>1)
10 const int maxnode = 200010;
11 struct Node{
12     int value;
13     int left, right;
14 }node[maxnode<<2];
15 void pushup(int rt){
16     node[rt].value = max(node[rt<<1].value, node[rt<<1|1].value);
17 }
18 void build(int l, int r, int rt){
19     node[rt].left=l, node[rt].right=r, node[rt].value=0;
20     if(l == r){
21         scanf("%d", &node[rt].value);
22         return;
23     }
24     int m = midf(l, r);
25     build(lson); build(rson);
26     pushup(rt);
27 }
28 void update(int a, int rt, int b){
29     if(node[rt].left==a && node[rt].right==a){
30         node[rt].value = b;
31         return;
32     }else{
33         int m = midf(node[rt].left, node[rt].right);
34         if(a <= m)  update(a, rt<<1, b);
35         if(a > m)  update(a, rt<<1|1, b);
36         pushup(rt);
37     }
38 }
39 int query(int l, int r, int rt){
40     if(node[rt].left>=l && node[rt].right<=r){
41         //这里注意,容易写错
42         return node[rt].value;
43     }
44     int ans = 0;
45     int m = midf(node[rt].left, node[rt].right);
46     if(l <= m) ans = max(ans, query(l, r, rt<<1));
47     if(r > m)  ans = max(ans, query(l, r, rt<<1|1));
48     return ans;
49 }
50 int main(){
51 //    freopen("in.txt", "r", stdin);
52     int n, m;
53     while(scanf("%d%d", &n, &m) != EOF){
54         build(1, n, 1);
55         for(int i=0; i<m; i++){
56             char ch[2];
57             scanf("%s", ch);
58             if(ch[0] == ‘Q‘){
59                 int l, r;
60                 scanf("%d%d", &l, &r);
61                 printf("%d\n", query(l, r, 1));
62             }else{
63                 int a, d;
64                 scanf("%d%d", &a, &d);
65                 update(a, 1, d);
66             }
67         }
68     }
69     return 0;
70 }

C - RMQ with Shifts

题意:shift(S):对序列S做一次(left “circular shift”)左移循环; query():查询区间最小值。

这里比较难想的是:关于shift()这里如何用线段树操作:按题意循环单点更新。这里需要提前保留第一个的值。

故此题变为:单点更新+查区间最小值

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxnode = 1e5+10;
 6 const int inf = 0x3f3f3f3f;
 7 #define lson l,m,rt<<1
 8 #define rson m+1,r,rt<<1|1
 9 #define midf(a,b) (((a)+(b))>>1)
10 struct Node{
11     int left, right;
12     int value;
13 }node[maxnode<<2];
14 //这里开空间要注意
15 void pushup(int rt){
16     node[rt].value = min(node[rt<<1].value, node[rt<<1|1].value);
17 }
18 void build(int l, int r, int rt){
19     node[rt].left=l, node[rt].right=r, node[rt].value=0;
20     if(l == r){
21         scanf("%d", &node[rt].value);
22         return;
23     }
24     int m = midf(l, r);
25     build(lson); build(rson);
26     pushup(rt);
27 }
28 int query(int l, int r, int rt){
29     if(node[rt].left>=l && node[rt].right<=r){
30         return node[rt].value;
31     }
32     int ans = inf, m = midf(node[rt].left, node[rt].right);
33     if(l<=m)  ans = min(ans, query(l, r, rt<<1));
34     if(r>m)   ans = min(ans, query(l, r, rt<<1|1));
35     return ans;
36 }
37 void update(int a, int rt, int b){
38     if(node[rt].left==a && node[rt].right==a){
39         node[rt].value = b;
40         return;
41     }
42     int m = midf(node[rt].left, node[rt].right);
43     if(a <= m) update(a, rt<<1, b);
44     else  update(a, rt<<1|1, b);
45     pushup(rt);
46 }
47 int query_node(int a, int rt){
48     if(node[rt].left==a && node[rt].right==a){
49         return node[rt].value;
50     }
51     int m = midf(node[rt].left, node[rt].right);
52     if(a<=m) return query_node(a, rt<<1);
53     else  return query_node(a, rt<<1|1);
54 }
55 int main(){
56 //    freopen("in.txt", "r", stdin);
57     int n, q;
58     scanf("%d%d", &n, &q);
59     build(1, n, 1);
60     for(int qq=0; qq<q; qq++){
61         char str[40];
62         scanf("%s", str);
63         if(str[0]==‘q‘){
64             int a=0, b=0, i;
65             for(i=6; str[i]!=‘,‘; i++){
66                 a = a*10 + (str[i]-‘0‘);
67             }
68             for(i=i+1; str[i]!=‘)‘; i++){
69                 b = b*10 + (str[i]-‘0‘);
70             }
71             printf("%d\n", query(a, b, 1));
72         }else{
73             int ch[40], len=0;
74             memset(ch, 0, sizeof(ch));
75             for(int i=6; str[i]!=‘)‘; i++){
76                 if(str[i]==‘,‘){
77                     len++;
78                 }
79                 else{
80                     ch[len] = ch[len]*10 + (str[i]-‘0‘);
81                 }
82             }
83             /*
84             cout << "ch[]:   ";
85             for(int i=0; i<=len; i++){
86                 cout << ch[i] << "   ";
87             }cout << endl;
88             */
89             int tmp = query_node(ch[0], 1);
90             for(int i=1; i<=len; i++){
91                 update(ch[i-1], 1, query_node(ch[i], 1));
92             }
93             update(ch[len], 1, tmp);
94         }
95     }
96     return 0;
97 }

D - A Simple Problem with Integers

区间内每个值均加相同值更新,查询区间求和

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxnode = 1e5+10;
 6 const int inf = 0x3f3f3f3f;
 7 #define LL long long
 8 #define lson l,m,rt<<1
 9 #define rson m+1,r,rt<<1|1
10 #define midf(a,b) (((a)+(b))>>1)
11 struct Node{
12     int left, right;
13     LL sum, add;
14 }node[maxnode<<2];
15
16 void pushup(int rt){
17     node[rt].sum = node[rt<<1].sum + node[rt<<1|1].sum;
18 }
19 void pushdown(int rt, int m){
20     if(node[rt].add){
21         node[rt<<1].add += node[rt].add;
22         node[rt<<1|1].add += node[rt].add;
23         node[rt<<1].sum += node[rt].add * (m - (m>>1));
24         node[rt<<1|1].sum += node[rt].add * (m>>1);
25         node[rt].add = 0;
26     }
27 }
28 void build(int l, int r, int rt){
29     node[rt].left=l, node[rt].right=r, node[rt].add=0;
30     if(l == r){
31         scanf("%lld", &node[rt].sum);
32         return;
33     }
34     int m = midf(l, r);
35     build(lson);
36     build(rson);
37     pushup(rt);
38 }
39 /*
40  * [l,r]内的每个数均加c, rt是根节点
41 */
42 void update(LL c, int l, int r, int rt){
43     if(l<=node[rt].left && node[rt].right<=r){
44         node[rt].add += c;
45         //add表示[l,r]的累加数,标记未下传
46         node[rt].sum += (LL)(node[rt].right-node[rt].left+1)*c;
47         //自己更新,并未更新子节点
48         return;
49     }
50     pushdown(rt, node[rt].right-node[rt].left+1);
51     //update要用到rt的子节点
52     int m = midf(node[rt].left, node[rt].right);
53     if(l <= m) update(c, l, r, rt<<1);
54     if(m < r)  update(c, l, r, rt<<1|1);
55     pushup(rt);
56 }
57 LL query(int l, int r, int rt){
58     if(l<=node[rt].left && node[rt].right<=r){
59         return node[rt].sum;
60     }
61     pushdown(rt, node[rt].right-node[rt].left+1);
62     LL ans = 0;
63     int m = midf(node[rt].left, node[rt].right);
64     if(l <= m) ans+=query(l, r, rt<<1);
65     if(m < r)  ans+=query(l, r, rt<<1|1);
66     return ans;
67 }
68 int main(){
69 //    freopen("in.txt", "r", stdin);
70     int n,q;
71     while(scanf("%d%d", &n, &q) != EOF){
72         build(1, n, 1);
73         while(q--){
74             char str[2];
75             scanf("%s", str);
76             int a, b, c;
77             if(str[0] == ‘C‘){
78                 scanf("%d%d%d", &a, &b, &c);
79                 update(c, a, b, 1);
80             }else{
81                 scanf("%d%d", &a, &b);
82                 printf("%lld\n", query(a, b, 1));
83             }
84         }
85     }
86     return 0;
87 }

E - Just a Hook

这题开始一直没有看到 You may consider the original hook is made up of cupreous sticks. 这句话,有点懵。

按要求为区间赋值最后求区间和。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxnode = 1e5+10;
 6 const int inf = 0x3f3f3f3f;
 7 #define LL long long
 8 #define lson l,m,rt<<1
 9 #define rson m+1,r,rt<<1|1
10 #define midf(a,b) (((a)+(b))>>1)
11 struct Node{
12     int left, right;
13     LL sum, add;
14 }node[maxnode<<2];
15 void pushup(int rt){
16     node[rt].sum = node[rt<<1].sum + node[rt<<1|1].sum;
17 }
18 void pushdown(int rt, int m){
19     if(node[rt].add){
20         node[rt<<1].add = node[rt].add;
21         node[rt<<1|1].add = node[rt].add;
22         node[rt<<1].sum = node[rt].add * (m - (m>>1));
23         node[rt<<1|1].sum = node[rt].add * (m>>1);
24         node[rt].add = 0;
25     }
26 }
27 void build(int l, int r, int rt){
28     node[rt].left=l, node[rt].right=r, node[rt].add=0;
29     if(l == r){
30         node[rt].sum = 1;
31         return;
32     }
33     int m = midf(l ,r);
34     build(lson);
35     build(rson);
36 }
37 void update(LL c, int l, int r, int rt){
38     if(l <= node[rt].left && node[rt].right<=r){
39         node[rt].add = c;
40         node[rt].sum = (LL)(node[rt].right - node[rt].left + 1) * c;
41         return;
42     }
43     pushdown(rt, node[rt].right-node[rt].left+1);
44     int m = midf(node[rt].left, node[rt].right);
45     if(l <= m) update(c, l, r, rt<<1);
46     if(m < r)  update(c, l, r, rt<<1|1);
47     pushup(rt);
48 }
49 LL query(int l, int r, int rt){
50     if(l <= node[rt].left && node[rt].right <= r){
51         return node[rt].sum;
52     }
53     pushdown(rt, node[rt].right-node[rt].left+1);
54     LL ans = 0;
55     int m = midf(node[rt].right, node[rt].left);
56     if(l <= m)  ans+=query(l, r, rt<<1);
57     if(m < r)   ans+=query(l, r, rt<<1|1);
58     return ans;
59 }
60 int main(){
61 //    freopen("in.txt", "r", stdin);
62     int tt;
63     scanf("%d", &tt);
64     for(int ttt=1; ttt<=tt; ttt++){
65         int n;  scanf("%d", &n);
66         build(1, n, 1);
67         int q;  scanf("%d", &q);
68         while(q--){
69             int l, r, a;
70             scanf("%d%d%d", &l, &r, &a);
71             update(a, l, r, 1);
72         }
73         printf("Case %d: The total value of the hook is %d.\n",ttt,query(1, n, 1));
74     }
75     return 0;
76 }

F - Count Color

题意:长度为L 的木棒,给T种颜色,两种操作:C:区间赋值  P:询问区间内颜色个数。

颜色这里由范围可知用状态压缩或运算处理。这里pushdown()操作向下更新子节点与前面题目不同的是这里是直接区间赋值,因为sum代表的是颜色。

其余的就是细心点,传递更新rt根节点信息时认真点。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 const int maxnode = 1e5+10;
 6 const int inf = 0x3f3f3f3f;
 7 #define LL long long
 8 #define lson l,m,rt<<1
 9 #define rson m+1,r,rt<<1|1
10 #define midf(a,b) (((a)+(b))>>1)
11 struct Node{
12     int left, right;
13     int sum, add;
14 }node[maxnode<<2];
15 void pushup(int rt){
16     node[rt].sum = node[rt<<1].sum | node[rt<<1|1].sum;
17 }
18 void pushdown(int rt){
19     if(node[rt].left == node[rt].right)return;
20     if(node[rt].add){
21         node[rt<<1].add = node[rt].add;
22         node[rt<<1|1].add = node[rt].add;
23         node[rt<<1].sum = node[rt].add;
24         node[rt<<1|1].sum = node[rt].add;
25         node[rt].add = 0;
26     }
27 }
28 void build(int l, int r, int rt){
29     node[rt].left=l, node[rt].right=r, node[rt].add=0;
30     if(l == r){
31         node[rt].sum=1;
32         return;
33     }
34     int m = midf(l, r);
35     build(lson);
36     build(rson);
37     pushup(rt);
38 }
39 void update(int c, int l ,int r, int rt){
40     if(l<=node[rt].left && node[rt].right<=r){
41         node[rt].sum = node[rt].add = c;
42         return;
43     }
44     pushdown(rt);
45     int m = midf(node[rt].left, node[rt].right);
46     if(l <= m)  update(c,l,r, rt<<1);
47     if(m < r)   update(c,l,r, rt<<1|1);
48     pushup(rt);
49 }
50 int query(int l, int r, int rt){
51     if(l<=node[rt].left && node[rt].right<=r){
52         return node[rt].sum;
53     }
54     pushdown(rt);
55     int m = midf(node[rt].left, node[rt].right);
56     int ans = 0;
57     if(l <= m) ans |= query(l,r, rt<<1);
58     if(m < r)  ans |= query(l,r, rt<<1|1);
59     return  ans;
60 }
61 int get_num(int c){
62     int tmp = 0;
63     while(c){
64         if(c & 1) tmp++;
65         c >>= 1;
66     }
67     return tmp;
68 }
69 int main(){
70 //    freopen("in.txt", "r", stdin);
71     int L, T, O;
72     while(scanf("%d%d%d", &L, &T, &O) != EOF){
73         build(1, L, 1);
74         while(O--){
75             char str[2];
76             scanf("%s", str);
77             if(str[0] == ‘C‘){
78                 int l, r, c;
79                 scanf("%d%d%d", &l, &r, &c);
80                 if(l>r)swap(l, r);
81                 update(1<<(c-1), l, r, 1);
82             }else{
83                 int l, r;
84                 scanf("%d%d", &l, &r);
85                 if(l>r)swap(l, r);
86                 printf("%d\n", get_num(query(l, r, 1)));
87             }
88         }
89     }
90     return 0;
91 }

G - Count the Colors(zoj1610)

题意:在[0,8000]的区间里染色[l, r],询问这个区间每种颜色所占的连续(颜色相同视为连续)区间的个数。

这道题看似与上道题目相似,可是坑点太多,写了很久,总是过不了样例,学了一些时间,也感觉收获很多。

这里先总结下我没考虑到的问题和思维上出错的地方:

1、上道题目染色给出的(l, r)代表的是从区间l区间r,而这道题目中染色(l, r)是代表从点l染色到点r,这里思考错,就gg了。

这个问题如何处理:其实不难,从原来维护点到现在维护单位区间,就将这个单位区间视为点。在code时什么时候更新(或查询或build)到点还是到区 间,需要注意。到点(l==r),到区间(l+1 == r)。

2、如何进行查询?这里写法难易与更新update()的写法有有关。先思考查询我们可以按遍历顺序进行判断前一个区间的颜色与当前区间的颜色是否相同来决定是否计数颜色,这种顺序可以视为先序遍历(这个思路感觉很神奇,反正我没想到)。然后是如何计数的问题,这里就需要对根节点做标记了,这个在3中讨论。

3、如何更新、计数?这里更新一定要更新到点才停止,查询是到区间才停止。如果更新到区间,会漏掉一种情况有可能就是当前这个区间,也有可能是如(l, m, rt<<1)和(m+1, r, rt<<1|1),这种会漏掉(m, m+1)这个单位区间。至于2中更新时如何对根节点进行标记,这里借助pushdown(),因为lazy操作后,需要用到子节点时,要将信息传递下去,同时标记根节点,可以在这个时候进行标记。我认为这是染色的精髓,当更新区间颜色时,导致左右子区间颜色不同时,进行标记,这其实是对区间的标记,代表其在计数时需要向下遍历。标记-2:左右子区间颜色不同。标记-1:这段区间未染色或者存在未染色的子区间。

上面的心得可能因表述能力写的有点乱。这道题目对现在的我来说真的是道很好的题,最然没有独立AC,但是学到了一些东西。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 using namespace std;
  5 const int maxnode = 8010;
  6 const int inf = 0x3f3f3f3f;
  7 #define LL long long
  8 #define lson l,m,rt<<1
  9 #define rson m,r,rt<<1|1
 10 #define midf(a,b) (((a)+(b))>>1)
 11 struct     Node{
 12     int left, right;
 13     int add;
 14 }node[maxnode<<2];
 15 void build(int l, int r, int rt){
 16     node[rt].left=l, node[rt].right=r, node[rt].add=-1;
 17     if(l+1 == r){
 18         return;
 19     }
 20     int m = midf(l, r);
 21     build(lson);
 22     build(rson);
 23     //rson = m,r,rt<<1|1
 24     //因为这里是区间的概念,要保证连续性
 25 }
 26 void pushdown(int rt){
 27     if(node[rt].add >= 0){
 28         node[rt<<1|1].add = node[rt<<1].add = node[rt].add;
 29         node[rt].add = -2;
 30     }
 31 }
 32 void update(int c, int l, int r, int rt){
 33     if((l == r) || (node[rt].add == c)){
 34         return;
 35     }
 36     /*
 37      * 这里剪枝掉两种情况:
 38      *  1、l==r: 这不是一个区间, 是一个点, 无法染色
 39      *  2、node[rt].add==c: rt点所在的大区间颜色相同。
 40     */
 41     if(l <= node[rt].left && node[rt].right <= r){
 42         node[rt].add = c;
 43         return;
 44     }
 45     pushdown(rt);
 46     //这里是染色的精髓,当更新区间颜色时,导致rt的左右子区间
 47     //颜色不同时,则标记node[rt].add=-2,代表其子区间颜色不同
 48     //心得:pushdown()在向下更新的同时,其实也可以对根节点做标记
 49     // 这种标记既可以作为信息已经下传的作用(清除lazy标记的意思吧)
 50     // 也可以对根进行特殊标记,这种标记的对象其实是区间。
 51     int m = midf(node[rt].left, node[rt].right);
 52     if(r <= m) update(c,l,r, rt<<1);
 53     else if(l >= m) update(c, l, r, rt<<1|1);
 54     else{
 55         update(c,lson);
 56         update(c,rson);
 57     }
 58     /*
 59     if(l <= m) update(c,l,r, rt<<1);
 60     if(m < r) update(c,l,r, rt<<1|1);
 61     这里会漏掉一种情况(m, m+1)这个区间
 62     而上面的else里:rson-->m,r,rt<<1|1
 63         并非平常的  rson-->m+1,r,rt<<1|1
 64     */
 65 }
 66 int ans[maxnode], color;
 67 void query(int rt){
 68     if(node[rt].add >= 0){
 69         //有区间,这段区内颜色相同
 70         if(node[rt].add != color){  //与前面区间的颜色比较
 71             ans[node[rt].add]++;
 72             color = node[rt].add;
 73         }
 74         return;
 75     }
 76     if(node[rt].left+1 != node[rt].right){
 77         //不是一个单位区间时(视单位区间为点)
 78         query(rt<<1);
 79         query(rt<<1|1);
 80     }else{
 81         // 这个线段没有颜色 或这是一个点
 82         color = -1;
 83     }
 84 }
 85 int main(){
 86 //    freopen("in.txt", "r", stdin);
 87     int n;
 88     while( scanf("%d", &n) != EOF){
 89         build(0, 8000, 1);
 90         //cout << "debug\n";
 91         for(int i=0; i<n; i++){
 92             int a, b, c;
 93             scanf("%d%d%d", &a, &b, &c);
 94             if(a >= b) continue;
 95             update(c, a, b, 1);
 96             //这里a+1则将单位线段视作一个点
 97         }
 98         color = -1; memset(ans, 0, sizeof(ans));
 99         query(1);
100         for(int i=0; i<maxnode; i++){
101             if(ans[i])
102                 printf("%d %d\n", i, ans[i]);
103         }
104         putchar(‘\n‘);
105     }
106     return 0;
107 }

上面几题内容有  区间加 区间赋值 区间替换(赋值)  询问区间和



还有3个部分待学。

原文地址:https://www.cnblogs.com/seaupnice/p/9515312.html

时间: 2024-10-21 00:31:58

线段树summer_work的相关文章

[poj2104]可持久化线段树入门题(主席树)

解题关键:离线求区间第k小,主席树的经典裸题: 对主席树的理解:主席树维护的是一段序列中某个数字出现的次数,所以需要预先离散化,最好使用vector的erase和unique函数,很方便:如果求整段序列的第k小,我们会想到离散化二分和线段树的做法, 而主席树只是保存了序列的前缀和,排序之后,对序列的前缀分别做线段树,具有差分的性质,因此可以求任意区间的第k小,如果主席树维护索引,只需要求出某个数字在主席树中的位置,即为sort之后v中的索引:若要求第k大,建树时反向排序即可 1 #include

【BZOJ4942】[Noi2017]整数 线段树+DFS(卡过)

[BZOJ4942][Noi2017]整数 题目描述去uoj 题解:如果只有加法,那么直接暴力即可...(因为1的数量最多nlogn个) 先考虑加法,比较显然的做法就是将A二进制分解成log位,然后依次更新这log位,如果最高位依然有进位,那么找到最高位后面的第一个0,将中间的所有1变成0,那个0变成1.这个显然要用到线段树,但是复杂度是nlog2n的,肯定过不去. 于是我在考场上yy了一下,这log位是连续的,我们每次都要花费log的时间去修改一个岂不是很浪费?我们可以先在线段树上找到这段区间

bzoj1798: [Ahoi2009]Seq 维护序列seq 线段树

题目传送门 这道题就是线段树 先传乘法标记再传加法 #include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=400010; LL read(){ LL ans=0,f=1,c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}

Vijos P1066 弱弱的战壕【多解,线段树,暴力,树状数组】

弱弱的战壕 描述 永恒和mx正在玩一个即时战略游戏,名字嘛~~~~~~恕本人记性不好,忘了-_-b. mx在他的基地附近建立了n个战壕,每个战壕都是一个独立的作战单位,射程可以达到无限(“mx不赢定了?!?”永恒[email protected][email protected]). 但是,战壕有一个弱点,就是只能攻击它的左下方,说白了就是横纵坐标都不大于它的点(mx:“我的战壕为什么这么菜”ToT).这样,永恒就可以从别的地方进攻摧毁战壕,从而消灭mx的部队. 战壕都有一个保护范围,同它的攻击

luogu 1712 区间(线段树+尺取法)

题意:给出n个区间,求选择一些区间,使得一个点被覆盖的次数超过m次,最小的花费.花费指的是选择的区间中最大长度减去最小长度. 坐标值这么大,n比较小,显然需要离散化,需要一个技巧,把区间转化为半开半闭区间,然后线段树的每一个节点表示一个半开半闭区间. 接着我们注意到需要求最小的花费,且这个花费只与选择的区间集合中的最大长度和最小长度有关. 这意味着如果最大长度和最小长度一定,我们显然是需要把中间长度的区间尽量的选择进去使答案不会变的更劣. 不妨把区间按长度排序,枚举每个最小长度区间,然后最大区间

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列

HDU 1754 I Hate It(线段树之单点更新,区间最值)

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 70863    Accepted Submission(s): 27424 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的

线段树入门总结

线段树的入门级 总结   线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点.      对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b].因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度.      使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN).而未优化的空间复杂度为2N,因此有时需要离散化让空间