• 线段树专题训练


    模块一:

    线段树单点更新,区间最值。

    http://acm.hdu.edu.cn/showproblem.php?pid=1166

    线段树功能:update:单点更新,query:区间求和。

    http://acm.hdu.edu.cn/showproblem.php?pid=1754

     线段树功能:update:单点更新,query:区间最值。

    PushUp(int rt) : 把当前节点的信息更新到父亲节点

    PushDown(int rt) :  把父亲节点的信息更新到儿子节点。

     1 /*************************************************************************
     2     > File Name: hdu1754.cpp
     3     > Author: syhjh
     4     > Created Time: 2014年03月20日 星期四 21时52分56秒
     5  ************************************************************************/
     6 #include <iostream>
     7 #include <cstdio>
     8 #include <cstring>
     9 #include <algorithm>
    10 using namespace std;
    11 
    12 #define lson rt << 1
    13 #define rson rt << 1 | 1
    14 const int MAXN = (200000 + 200);
    15 template < class T > inline T getMax(const T &a, const T &b)
    16 {
    17     return a > b ? a : b;
    18 }
    19 
    20 int sum[MAXN << 2];
    21 int N, M;
    22 
    23 void PushUp(int rt)
    24 {
    25     sum[rt] = getMax(sum[lson], sum[rson]);
    26 }
    27 
    28 void Build(int L, int R, int rt)
    29 {
    30     if (L == R) {
    31         scanf("%d", &sum[rt]);
    32         return;
    33     }
    34     int M = (L + R) >> 1;
    35     Build(L, M, lson);
    36     Build(M + 1, R, rson);
    37     PushUp(rt);
    38 }
    39 
    40 void Update(int L, int R, int rt, int p, int x)
    41 {
    42     if (L == R) {
    43         sum[rt] = x;
    44         return;
    45     }
    46     int M = (L + R) >> 1;
    47     if (p <= M) {
    48         Update(L, M, lson, p, x);
    49     } else 
    50         Update(M + 1, R, rson, p, x);
    51     PushUp(rt);
    52 }
    53 
    54 int Query(int L, int R, int rt, int l, int r)
    55 {
    56     if (l <= L && R <= r) {
    57         return sum[rt];
    58     }
    59     int M = (L + R) >> 1;
    60     int res = 0;
    61     if (l <= M) res = getMax(res, Query(L, M, lson, l, r));
    62     if (r > M) res = getMax(res, Query(M + 1, R, rson, l, r));
    63     return res;
    64 }
    65 
    66 int main()
    67 {
    68     while (cin >> N >> M) {
    69         Build(1, N, 1);
    70         while (M--) {
    71             char str[11];
    72             int x, y;
    73             scanf("%s", str);
    74             if (str[0] == 'U') {
    75                 scanf("%d %d", &x, &y);
    76                 Update(1, N, 1, x, y);
    77             } else if (str[0] == 'Q') {
    78                 scanf("%d %d", &x, &y);
    79                 int ans =  Query(1, N, 1, x, y);
    80                 printf("%d
    ", ans);
    81             }
    82         }
    83     }
    84     return 0;
    85 }
    View Code

     http://acm.hdu.edu.cn/showproblem.php?pid=1394

    可以先求开始序列的逆序数,一开始记录每个叶子节点的值为0,然后对于每个数,插入之后更新一下,对于当前的x[i],需要插叙[x[i], n - 1]之间的数已经出现了多少个。求出一开始的逆序数之后,就可以通过递推关系式以此找出后面的逆序数对。

     1 #define _CRT_SECURE_NO_WARNINGS
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 #define lson rt << 1
     9 #define rson rt << 1 | 1
    10 const int MAXN = (5000 + 50);
    11 template < class T > inline T getMIN(const T &a, const T &b)
    12 {
    13     return a < b ? a : b;
    14 }
    15 int sum[MAXN << 2];
    16 
    17 void PushUp(int rt)
    18 {
    19     sum[rt] = sum[lson] + sum[rson];
    20 }
    21 
    22 void Build(int L, int R, int rt)
    23 {
    24     sum[rt] = 0;
    25     if (L == R) return;
    26     int M = (L + R) >> 1;
    27     Build(L, M, lson);
    28     Build(M + 1, R, rson);
    29 }
    30 
    31 void Update(int L, int R, int rt, int p)
    32 {
    33     if (L == R) {
    34         sum[rt]++;
    35         return;
    36     }
    37     int M = (L + R) >> 1;
    38     if (p <= M) Update(L, M, lson, p);
    39     else Update(M + 1, R, rson, p);
    40     PushUp(rt);
    41 }
    42 
    43 int Query(int L, int R, int rt, int l, int r)
    44 {
    45     if (l <= L && R <= r) {
    46         return sum[rt];
    47     }
    48     int M = (L + R) >> 1;
    49     int ret = 0;
    50     if (l <= M) ret += Query(L, M, lson, l, r);
    51     if (r > M) ret += Query(M + 1, R, rson, l, r);
    52     return ret;
    53 }
    54 
    55 int n, num[MAXN];
    56 int main()
    57 {
    58     while (~scanf("%d", &n)) {
    59         for (int i = 0; i < n; i++) {
    60             scanf("%d", &num[i]);
    61         }
    62         Build(0, n - 1, 1);
    63         int sum = 0;
    64         for (int i = 0; i < n; i++) {
    65             sum += Query(0, n - 1, 1, num[i], n - 1);
    66             Update(0, n - 1, 1, num[i]);
    67         }
    68         int ans = sum;
    69         for (int i = 0; i < n; i++) {
    70             sum += (n - num[i] - 1) - num[i];
    71             ans = getMIN(ans, sum);
    72         }
    73         printf("%d
    ", ans);
    74     }
    75     return 0;
    76 }
    View Code

    http://acm.hdu.edu.cn/showproblem.php?pid=2795

    这题的本质是区间最大值,这是线段树的长处。

    叶子节点x表示board的x行还能放的长度,于是对于区间[a, b]就是表示第a行到b行所能放的最大的长度,那么我们可以从根节点开始比较,如果当前长度小于跟节点的值,就往左子树走,否则就往右子树走,达到叶子节点的时候,len[rt] -= x表示在这一行放置了长度为x的广告,于是剩下的长度就要减少了,然后在update就可以了。

     1 #define _CRT_SECURE_NO_WARNINGS
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 #define lson rt << 1
     9 #define rson rt << 1 | 1
    10 const int MAXN = (200000 + 20);
    11 int h, w, n;
    12 int len[MAXN << 2];
    13 
    14 template< class T > inline T getMIN(const T &a, const T &b)
    15 {
    16     return a < b ? a : b;
    17 }
    18 
    19 template< class T > inline T getMAX(const T &a, const T &b)
    20 {
    21     return a > b ? a : b;
    22 }
    23 
    24 void PushUp(int rt)
    25 {
    26     len[rt] = getMAX(len[lson], len[rson]);
    27 }
    28 
    29 void Build(int L, int R, int rt)
    30 {
    31     len[rt] = w;
    32     if (L == R) return;
    33     int M = (L + R) >> 1;
    34     Build(L, M, lson);
    35     Build(M + 1, R, rson);
    36 }
    37 
    38 int Query(int L, int R, int rt, int x)
    39 {
    40     if (L == R) {
    41         len[rt] -= x;
    42         return L;
    43     }
    44     int M = (L + R) >> 1;
    45     int ret = (len[lson] >= x ? Query(L, M, lson, x) : Query(M + 1, R, rson, x));
    46     PushUp(rt);
    47     return ret;
    48 }
    49 
    50 int main()
    51 {
    52     int x;
    53     while (~scanf("%d %d %d", &h, &w, &n)) {
    54         h = getMIN(h, n);
    55         Build(1, h, 1);
    56         for (int i = 1; i <= n; i++) {
    57             scanf("%d", &x);
    58             if (x > len[1]) {
    59                 puts("-1");
    60                 continue;
    61             }
    62             printf("%d
    ", Query(1, h, 1, x));
    63         }
    64     }
    65     return 0;
    66 }
    View Code

    http://poj.org/problem?id=2828

    采用倒序插入,pos的意义就是找到一个位置,它的前面刚好有pos个空位,用一个empty数组记录区间[l,r]之间有多少个空位,然后进来一个p,比较左右子树的空位数,如果坐标的空位数 >= p,那么说明p应该放在左子树,否则,p应该放右子树,并且p还要减去左子树的空位数,因为右子树的空位数也是从0开始的。

     1 #define  _CRT_SECURE_NO_WARNINGS
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 #define lson rt << 1
     9 #define rson rt << 1 | 1
    10 const int MAXN = (200000 + 20);
    11 int empty[MAXN << 2];
    12 int n, index, pos[MAXN], id[MAXN], ans[MAXN];
    13 
    14 void Build(int L, int R, int rt)
    15 {
    16     empty[rt] = R - L + 1;
    17     if (L == R) return;
    18     int M = (L + R) >> 1;
    19     Build(L, M, lson);
    20     Build(M + 1, R, rson);
    21 }
    22 
    23 void Update(int L, int R, int rt, int p)
    24 {
    25     empty[rt]--;
    26     if (L == R) {
    27         index = L;
    28         return;
    29     }
    30     int M = (L + R) >> 1;
    31     if (empty[lson] >= p) Update(L, M, lson, p);
    32     else p -= empty[lson], Update(M + 1, R, rson, p);
    33 }
    34 
    35 int main()
    36 {
    37     while (~scanf("%d", &n)) {
    38         for (int i = 1; i <= n; i++) {
    39             scanf("%d %d", &pos[i], &id[i]);
    40         }
    41         Build(1, n, 1);
    42         for (int i = n; i >= 1; i--) {
    43             Update(1, n, 1, pos[i] + 1);
    44             ans[index] = id[i];
    45         }
    46         for (int i = 1; i <= n; i++) {
    47             printf(i == n ? "%d
    " : "%d ", ans[i]);
    48         }
    49     }
    50     return 0;
    51 }
    View Code

    http://poj.org/problem?id=2481

    对n头牛先按S从小到大排序,在按E从大到小排序,这样每次计算一个,我们可以找比当前的e大的出现的数目,然后更新即可,线段树的查找和更新的复杂度均为n * log(n).

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 #define lson rt << 1
     8 #define rson rt << 1 | 1
     9 const int MAXN = (100000 + 100);
    10 template< typename T > inline T getMAX(const T &a, const T &b)
    11 {
    12     return a > b ? a : b;
    13 }
    14 
    15 struct Node {
    16     int s, e, id;
    17 } node[MAXN];
    18 
    19 int cmp(const Node &p, const Node &q)
    20 {
    21     if (p.s != q.s) {
    22         return p.s < q.s;
    23     }
    24     return p.e > q.e;
    25 }
    26 
    27 int N;
    28 int sum[MAXN << 2];
    29 
    30 void PushUp(int rt)
    31 {
    32     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    33 }
    34 
    35 void Build(int L, int R, int rt)
    36 {
    37     sum[rt] = 0;
    38     if (L == R) return;
    39     int M = (L + R) >> 1;
    40     Build(L, M, lson);
    41     Build(M + 1, R, rson);
    42 }
    43 
    44 void Update(int L, int R, int rt, int p)
    45 {
    46     if (L == R) {
    47         sum[rt]++;
    48         return;
    49     }
    50     int M = (L + R) >> 1;
    51     if (p <= M) Update(L, M, lson, p);
    52     else Update(M + 1, R, rson, p);
    53     PushUp(rt);
    54 }
    55 
    56 int Query(int L, int R, int rt, int l, int r)
    57 {
    58     if (l <= L && R <= r) {
    59         return sum[rt];
    60     }
    61     int M = (L + R) >> 1;
    62     int ret = 0;
    63     if (l <= M) ret += Query(L, M, lson, l, r);
    64     if (r > M) ret += Query(M + 1, R, rson, l, r);
    65     return ret;
    66 }
    67 
    68 
    69 int ans[MAXN];
    70 int MAX;
    71 int main()
    72 {
    73     while (~scanf("%d", &N) && N) {
    74         MAX = 0;
    75         for (int i = 0; i < N; i++) {
    76             scanf("%d %d", &node[i].s, &node[i].e);
    77             MAX = getMAX(MAX, node[i].e);
    78             node[i].id = i;
    79         }
    80         sort(node, node + N, cmp);
    81         Build(1, MAX, 1);
    82         ans[node[0].id] = 0;
    83         Update(1, MAX, 1, node[0].e);
    84         for (int i = 1; i < N; i++) {
    85             if (node[i].s == node[i - 1].s && node[i].e == node[i - 1].e) {
    86                 ans[node[i].id] = ans[node[i - 1].id];
    87             } else
    88                 ans[node[i].id] = Query(1, MAX, 1, node[i].e, MAX);
    89             Update(1, MAX, 1, node[i].e);
    90         }
    91         for (int i = 0; i < N; i++) {
    92             if (i == N - 1) printf("%d
    ", ans[i]);
    93             else printf("%d ", ans[i]);
    94         }
    95     }
    96     return 0;
    97 }
    View Code

    http://poj.org/problem?id=2182

    len数组代表当前节点的区间还有的空位置,那么我们可以从后往前依次放位置,这样就能确定最后的序列了!

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 #define lson rt << 1
     8 #define rson rt << 1 | 1
     9 const int MAXN = (8000 + 80);
    10 int len[MAXN << 2];
    11 int num[MAXN], ans[MAXN], pos, N;
    12 
    13 void Build(int L, int R, int rt)
    14 {
    15     len[rt] = R - L + 1;
    16     if (L == R) return;
    17     int M = (L + R) >> 1;
    18     Build(L, M, lson);
    19     Build(M + 1, R, rson);
    20 }
    21 
    22 void Update(int L, int R, int rt, int p)
    23 {
    24     len[rt]--;
    25     if (L == R) {
    26         pos = L;
    27         return;
    28     }
    29     int M = (L + R) >> 1;
    30     if (p <= len[lson]) Update(L, M, lson, p);
    31     else Update(M + 1, R, rson, p - len[lson]);
    32 }
    33 
    34 int main()
    35 {
    36     while (~scanf("%d", &N)) {
    37         num[1] = 0;
    38         for (int i = 2; i <= N; i++) {
    39             scanf("%d", &num[i]);
    40         }
    41         Build(1, N, 1);
    42         for (int i = N; i >= 1; i--) {
    43             Update(1, N, 1, num[i] + 1);
    44             ans[i] = pos;
    45         }
    46         for (int i = 1; i <= N; i++) {
    47             printf("%d
    ", ans[i]);
    48         }
    49     }
    50     return 0;
    51 }
    View Code

     模块二:线段树成段更新。

    http://acm.hdu.edu.cn/showproblem.php?pid=1698

    col数组要来标记当前区间的值,一开始所有的区间都为0,然后我们更新的时候,如果当前的区间的col不为0,则说明该区间是纯的,此时,我们应该把这个区间的col往左右子树传,同时计算sum的值,由于是纯的,因此当前节点的左子树和当前节点的右子树的sum可以直接求得,然后在把当前的col改为0,表示当前节点覆盖的区间不纯。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 #define lson rt << 1
     8 #define rson rt << 1 | 1
     9 const int MAXN = (100000 + 100);
    10 int N, M;
    11 int col[MAXN << 2], sum[MAXN << 2];
    12 
    13 void PushDown(int rt, int len)
    14 {
    15     if (col[rt]) {
    16         col[lson] = col[rson] = col[rt];
    17         sum[lson] = (len - (len >> 1)) * col[rt];
    18         sum[rson] = (len >> 1) * col[rt];
    19         col[rt] = 0; //不纯洁
    20     }
    21 }
    22 
    23 void PushUp(int rt)
    24 {
    25     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    26 }
    27 
    28 
    29 void Build(int L, int R, int rt)
    30 {
    31     col[rt] = 0;
    32     sum[rt] = 1;
    33     if (L == R) return;
    34     int M = (L + R) >> 1;
    35     Build(L, M, lson);
    36     Build(M + 1, R, rson);
    37     PushUp(rt);
    38 }
    39 
    40 void Update(int L, int R, int rt, int l, int r, int color)
    41 {
    42     if (l <= L && R <= r) {
    43         col[rt] = color;
    44         sum[rt] = (R - L + 1) * color;
    45         return;
    46     }
    47     PushDown(rt, R - L + 1);
    48     int M = (L + R) >> 1;
    49     if (l <= M) Update(L, M, lson, l, r, color);
    50     if (r > M) Update(M + 1, R, rson, l, r, color);
    51     PushUp(rt);
    52 }
    53 
    54 int main()
    55 {
    56     int Cas, t = 1;
    57     scanf("%d", &Cas);
    58     while (Cas--) {
    59         scanf("%d %d", &N, &M);
    60         Build(1, N, 1);
    61         for (int i = 0; i < M; i++) {
    62             int a, b, c;
    63             scanf("%d %d %d", &a, &b, &c);
    64             Update(1, N, 1, a, b, c);
    65         }
    66         printf("Case %d: The total value of the hook is %d.
    ", t++, sum[1]);
    67     }
    68     return 0;
    69 }
    View Code

    http://poj.org/problem?id=3468

    线段树成段更新,采用lazy思想,记录增量,更新的时候只更新到段,等到下次更新或者查询的时候,碰到已经被标记过的,往下顺延就行。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 #define lson rt << 1
     8 #define rson rt << 1 | 1
     9 typedef long long ll;
    10 const int MAXN = (100000 +100);
    11 int N, Q;
    12 ll sum[MAXN << 2], add[MAXN << 2];
    13 
    14 void PushUp(int rt)
    15 {
    16     sum[rt] = sum[lson] + sum[rson];
    17 }
    18 
    19 void PushDown(int rt, int len)
    20 {
    21     if (add[rt]) {
    22         add[lson] += add[rt];
    23         add[rson] += add[rt];
    24         sum[lson] += (len - (len >> 1)) * add[rt];
    25         sum[rson] += (len >> 1) * add[rt];
    26         add[rt] = 0;
    27     }
    28 }
    29 
    30 void Build(int L, int R, int rt)
    31 {
    32     add[rt] = 0;
    33     if (L == R) {
    34         scanf("%lld", &sum[rt]);
    35         return;
    36     }
    37     int M = (L + R) >> 1;
    38     Build(L, M, lson);
    39     Build(M + 1, R, rson);
    40     PushUp(rt);
    41 }
    42 
    43 void Update(int L, int R, int rt, int l, int r, int lnc)
    44 {
    45     if (l <= L && R <= r) {
    46         add[rt] += lnc;
    47         sum[rt] += (R - L + 1) * lnc;
    48         return;
    49     }
    50     PushDown(rt, R - L + 1);
    51     int M = (L + R) >> 1;
    52     if (l <= M) Update(L, M, lson, l, r, lnc);
    53     if (r > M) Update(M + 1, R, rson, l, r, lnc);
    54     PushUp(rt);
    55 }
    56 
    57 ll Query(int L, int R, int rt, int l, int r)
    58 {
    59     if (l <= L && R <= r) {
    60         return sum[rt];
    61     }
    62     PushDown(rt, R - L + 1);
    63     int M = (L + R) >> 1;
    64     ll ret = 0;
    65     if (l <= M) ret += Query(L, M, lson, l, r);
    66     if (r > M) ret += Query(M + 1, R, rson, l, r);
    67     return ret;
    68 }
    69 
    70 int main()
    71 {
    72     scanf("%d %d", &N, &Q);
    73     Build(1, N, 1);
    74     while (Q--) {
    75         char str[2];
    76         int a, b, c;
    77         scanf("%s", str);
    78         if (str[0] == 'Q') {
    79             scanf("%d %d", &a, &b);
    80             printf("%lld
    ", Query(1, N, 1, a, b));
    81         } else if (str[0] == 'C') {
    82             scanf("%d %d %d", &a, &b, &c);
    83             Update(1, N, 1, a, b, c);
    84         }
    85     }
    86     return 0;
    87 }
    View Code

    http://acm.cug.edu.cn/JudgeOnline/problem.php?id=1435

    线段树成段更新,区间最值。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 #define lson rt << 1
      8 #define rson rt << 1 | 1
      9 typedef long long ll;
     10 const int MAXN = (100000 + 100);
     11 template < typename T > inline T getMIN(const T &a, const T &b)
     12 {
     13     return a < b ? a : b;
     14 }
     15 
     16 int N, M;
     17 ll MIN[MAXN << 2], add[MAXN << 2];
     18 
     19 void PushDown(int rt)
     20 {
     21     if (add[rt]) {
     22         add[lson] += add[rt];
     23         add[rson] += add[rt];
     24         MIN[lson] += add[rt];
     25         MIN[rson] += add[rt];
     26         add[rt] = 0;
     27     }
     28 }
     29 
     30 void PushUp(int rt)
     31 {
     32     MIN[rt] = getMIN(MIN[lson], MIN[rson]);
     33 }
     34 
     35 void Build(int L, int R, int rt)
     36 {
     37     add[rt] = 0;
     38     if (L == R) {
     39         scanf("%lld", &MIN[rt]);
     40         return;
     41     }
     42     int M = (L + R) >> 1;
     43     Build(L, M, lson);
     44     Build(M + 1, R, rson);
     45     PushUp(rt);
     46 }
     47 
     48 void Update(int L, int R, int rt, int l, int r, int lnc)
     49 {
     50     if (l <= L && R <= r) {
     51         add[rt] += lnc;
     52         MIN[rt] += lnc;
     53         return;
     54     }
     55     PushDown(rt);
     56     int M = (L + R) >> 1;
     57     if (l <= M) Update(L, M, lson, l, r, lnc);
     58     if (r > M) Update(M + 1, R, rson, l, r, lnc);
     59     PushUp(rt);
     60 }
     61 
     62 ll Query(int L, int R, int rt, int l, int r)
     63 {
     64     if (l <= L && R <= r) {
     65         return MIN[rt];
     66     }
     67     PushDown(rt);
     68     int M = (L + R) >> 1;
     69     ll ans = 1LL << 60;
     70     if (l <= M) ans = getMIN(ans, Query(L, M, lson, l, r));
     71     if (r > M) ans = getMIN(ans, Query(M + 1, R, rson, l, r));
     72     return ans;
     73 }
     74 
     75 int Judge(char *str)
     76 {
     77     int len = strlen(str), cnt = 0;
     78     for (int i = 0; i < len; ) {
     79         if (str[i] == ' ') {
     80             cnt++;
     81             while (i < len && str[i] == ' ') i++;
     82         } else
     83             i++;
     84     }
     85     return cnt;
     86 }
     87 
     88 int main()
     89 {
     90     while (~scanf("%d %d", &N, &M)) {
     91         Build(0, N - 1, 1);
     92         getchar();
     93         while (M--) {
     94             char str[22];
     95             int a, b, c;
     96             gets(str);
     97             if (Judge(str) == 1) {
     98                 sscanf(str, "%d %d", &a, &b);
     99                 if (a <= b) {
    100                     printf("%lld
    ", Query(0, N - 1, 1, a, b));
    101                 } else
    102                     printf("%lld
    ", getMIN(Query(0, N - 1, 1, a, N - 1), Query(0, N - 1, 1, 0, b)));
    103             } else if (Judge(str) == 2) {
    104                 sscanf(str, "%d %d %d", &a, &b, &c);
    105                 if (a <= b) {
    106                     Update(0, N - 1, 1, a, b, c);
    107                 } else {
    108                     Update(0, N - 1, 1, 0, b, c);
    109                     Update(0, N - 1, 1, a, N - 1, c);
    110                 }
    111             }
    112         }
    113     }
    114     return 0;
    115 }
    View Code

    http://poj.org/problem?id=2528

    线段树 + 离散化。

    http://www.notonlysuccess.com/index.php/segment-tree-complete/大牛的博客讲得很清楚!

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 #define lson rt << 1
     8 #define rson rt << 1 | 1
     9 const int MAXN = (100000 + 100);
    10 struct Node {
    11     int l, r;
    12 } node[MAXN];
    13 
    14 bool Hash[MAXN];
    15 int X[MAXN << 2];
    16 int col[MAXN << 4];
    17 int cnt, n, m;
    18 
    19 void PushDown(int rt)
    20 {
    21     if (col[rt] != -1) {
    22         col[lson] = col[rson] = col[rt];
    23         col[rt] = -1;
    24     }
    25 }
    26 
    27 void Update(int L, int R, int rt, int l, int r, int color)
    28 {
    29     if (l <= L && R <= r) {
    30         col[rt] = color;
    31         return;
    32     }
    33     PushDown(rt);
    34     int M = (L + R) >> 1;
    35     if (l <= M) Update(L, M, lson, l, r, color);
    36     if (r > M) Update(M + 1, R, rson, l, r, color);
    37 }
    38 
    39 void Query(int L, int R, int rt)
    40 {
    41     if (col[rt] != -1) {
    42         if (!Hash[col[rt]]) cnt++;
    43         Hash[col[rt]] = true;
    44         return;
    45     }
    46     if (L == R) return;
    47     int M = (L + R) >> 1;
    48     Query(L, M, lson);
    49     Query(M + 1, R, rson);
    50 }
    51 
    52 int Binary_Search(int low, int high, int number)
    53 {
    54     while (low <= high) {
    55         int mid = (low + high) >> 1;
    56         if (X[mid] == number) return mid;
    57         else if (X[mid] < number) low = mid +1;
    58         else high = mid - 1;
    59     }
    60     return low;
    61 }
    62 
    63 int main()
    64 {
    65     int Cas;
    66     scanf("%d", &Cas);
    67     while (Cas--) {
    68         scanf("%d", &m);
    69         cnt = n = 0;
    70         for (int i = 0; i < m; i++) {
    71             scanf("%d %d", &node[i].l, &node[i].r);
    72             X[n++] = node[i].l;
    73             X[n++] = node[i].r;
    74         }
    75         sort(X, X + n);
    76         n = unique(X, X + n) - X;
    77         for (int i = n - 1; i > 0; i--) {
    78             if (X[i] != X[i - 1] + 1) X[n++] = X[i - 1] + 1;
    79         }
    80         sort(X, X + n);
    81         memset(col, -1, sizeof(col));
    82         for (int i = 0; i < m; i++) {
    83             int l = Binary_Search(0, n - 1, node[i].l);
    84             int r = Binary_Search(0, n - 1, node[i].r);
    85             Update(0, n - 1, 1, l, r, i);
    86         }
    87         memset(Hash, false, sizeof(Hash));
    88         Query(0, n - 1, 1);
    89         printf("%d
    ", cnt);
    90     }
    91     return 0;
    92 }
    View Code

    http://poj.org/problem?id=3225

    线段树:区间异或,成段更新。

    集合操作:

    U: 把区间[l, r]覆盖成1

    I: 把区间(-oo, l)和(r, +oo)覆盖成0

    D:把区间(l, r) 覆盖成0

    C: 把区间(-oo, l)和(r, +oo)覆盖成0,并且把[l, r]区间0、1互换

    S: 把区间[l, r]0、1互换

    0、1互换的过程实际上也就是异或的过程;

    成段更新操作与之前的类似,不同的是异或的操作。

    显然,当一个区间被覆盖后,不管之前有没有异或标记都没有意义了,因此应该把异或标记清0;

    当一个节点得到异或标记的时候,应该先判断该节点的覆盖标记,如果该节点的覆盖标记为0/1(标记为-1,表示不是完全包含或者完全不包含),直接改变覆盖标记,否则改变异或标记。

    至于如果来区别开闭区间,我们可以将区间扩大两倍,即:

    左闭:x - > 2 * x 

    左开: x - > 2 * x + 1

    右闭:y - > 2 * y;

    右开: y - > 2 * y - 1

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 using namespace std;
      6 
      7 #define lson rt << 1
      8 #define rson rt << 1 | 1
      9 const int MAXN  = (65537 << 1);
     10 bool mark[MAXN];
     11 int cover[MAXN << 2];
     12 int XOR[MAXN << 2];
     13 
     14 void FXOR(int rt)
     15 {
     16     if (cover[rt] != -1) {
     17         cover[rt] ^= 1;
     18     } else
     19         XOR[rt] ^= 1;
     20 }
     21 
     22 void PushDown(int rt)
     23 {
     24     if (cover[rt] != -1) {
     25         cover[lson] = cover[rson] = cover[rt];
     26         XOR[lson] = XOR[rson] = 0;
     27         cover[rt] = -1;
     28     }
     29     if (XOR[rt]) {
     30         FXOR(lson);
     31         FXOR(rson);
     32         XOR[rt] = 0;
     33     }
     34 }
     35 
     36 void Update(int L, int R, int rt, int l, int r, char ch)
     37 {
     38     if (l <= L && R <= r) {
     39         if (ch == 'U') {
     40             cover[rt] = 1;
     41             XOR[rt] = 0;
     42         } else if (ch == 'D') {
     43             cover[rt] = 0;
     44             XOR[rt] = 0;
     45         } else if (ch == 'C' || ch == 'S') {
     46             FXOR(rt);
     47         }
     48         return;
     49     }
     50     PushDown(rt);
     51     int M = (L + R) >> 1;
     52     if (l <= M) Update(L, M, lson, l, r, ch);
     53     else if (ch == 'I' || ch == 'C') {
     54         XOR[lson] = cover[lson] = 0;
     55     }
     56     if (r > M) Update(M + 1, R, rson, l, r, ch);
     57     else if (ch == 'I' || ch == 'C') {
     58         XOR[rson] = cover[rson] = 0;
     59     }
     60 }
     61 
     62 void Query(int L, int R, int rt)
     63 {
     64     if (cover[rt] != -1) {
     65         if (cover[rt] == 1) {
     66             for (int i = L; i <= R; i++) {
     67                 mark[i] = true;
     68             }
     69         }
     70         return;
     71     }
     72     PushDown(rt);
     73     int M = (L + R) >> 1;
     74     Query(L, M, lson);
     75     Query(M + 1, R, rson);
     76 }
     77 
     78 int main()
     79 {
     80     cover[1] = XOR[1] = 0;
     81     char ch, op1, op2;
     82     int a, b;
     83     memset(mark, false, sizeof(mark));
     84     while (~scanf("%c %c%d,%d%c
    ", &ch, &op1, &a, &b, &op2)) {
     85         a <<= 1;
     86         b <<= 1;
     87         if (op1 == '(') {
     88             a++;
     89         }
     90         if (op2 == ')') {
     91             b--;
     92         }
     93         if (a > b) {
     94             if (ch == 'I' || ch == 'C') {
     95                 cover[1] = XOR[1] = 0;
     96             }
     97         } else
     98             Update(0, MAXN, 1, a, b, ch);
     99     }
    100     Query(0, MAXN, 1);
    101     bool flag = false;
    102     int st = -1, ed;
    103     for (int i = 0; i <= MAXN; i++) {
    104         if (mark[i]) {
    105             if (st == -1) st = i;
    106             ed = i;
    107         } else {
    108             if (st != -1) {
    109                 if (flag) printf(" ");
    110                 flag = true;
    111                 printf("%c%d,%d%c", st & 1 ? '(' : '[', st >> 1, (ed + 1) >> 1, ed & 1 ? ')' : ']');
    112                 st = -1;
    113             }
    114         }
    115     }
    116     if (!flag) printf("empty set");
    117     puts("");
    118     return 0;
    119 }
    View Code
  • 相关阅读:
    10
    9
    8
    第七章
    第五章
    第六章
    android深度探索第四章
    android深度探索第三章
    android深度探索第二章
    android深度探索第一章
  • 原文地址:https://www.cnblogs.com/wally/p/3614721.html
Copyright © 2020-2023  润新知