线段树中区间加减和区间覆盖的双标记问题

Posted wangwangyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树中区间加减和区间覆盖的双标记问题相关的知识,希望对你有一定的参考价值。

HDU 5828

吉老师真厉害。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define lson q << 1
  4 #define rson (q << 1) | 1
  5 #define mid ((l + r) >> 1)
  6 typedef long long ll;
  7 const int maxn = 1e5 + 50;
  8 ll maxv[maxn << 2];
  9 ll minv[maxn << 2];
 10 ll sum[maxn << 2];
 11 ll lazy[maxn << 2];
 12 ll cover[maxn << 2];
 13 int segl[maxn << 2], segr[maxn << 2];
 14 int a[maxn];
 15 void push_up(int q)
 16 {
 17     maxv[q] = max(maxv[lson], maxv[rson]);
 18     minv[q] = min(minv[lson], minv[rson]);
 19     sum[q] = sum[lson] + sum[rson];
 20 }
 21 void build(int q, int l, int r)
 22 {
 23     lazy[q] = cover[q] = 0;
 24     segl[q] = l, segr[q] = r;
 25     maxv[q] = minv[q] = sum[q] = 0;
 26     if(l == r)
 27     {
 28         sum[q] = maxv[q] = minv[q] = a[l];
 29         return;
 30     }
 31     build(lson, l, mid);
 32     build(rson, mid + 1, r);
 33     push_up(q);
 34 }
 35 void push_down(int q)
 36 {
 37     if(cover[q])
 38     {
 39         maxv[lson] = minv[lson] = cover[q] + lazy[q];
 40         cover[lson] = minv[lson];
 41         sum[lson] = (ll)(segr[lson] - segl[lson] + 1) * minv[lson];
 42         maxv[rson] = minv[rson] = cover[q] + lazy[q];
 43         cover[rson] = minv[rson];
 44         sum[rson] = (ll)(segr[rson] - segl[rson] + 1) * minv[rson];
 45         lazy[q] = cover[q] = lazy[lson] = lazy[rson] = 0;
 46     }
 47     else if(lazy[q])
 48     {
 49         lazy[lson] += lazy[q];
 50         minv[lson] += lazy[q];
 51         maxv[lson] += lazy[q];
 52         sum[lson] += (ll)(segr[lson] - segl[lson] + 1) * lazy[q];
 53         lazy[rson] += lazy[q];
 54         minv[rson] += lazy[q];
 55         maxv[rson] += lazy[q];
 56         sum[rson] += (ll)(segr[rson] - segl[rson] + 1) * lazy[q];
 57         lazy[q] = 0;
 58     }
 59 }
 60 void change(int q, int l, int r, int ql, int qr, int x)
 61 {
 62     if(qr < l || ql > r) return;
 63     if(ql <= l && qr >= r)
 64     {
 65         lazy[q] += x;
 66         maxv[q] += x;
 67         minv[q] += x;
 68         sum[q] += (ll)(r - l + 1) * x;
 69         return;
 70     }
 71     push_down(q);
 72     change(lson, l, mid, ql, qr, x);
 73     change(rson, mid + 1, r, ql, qr, x);
 74     push_up(q);
 75 }
 76 void change(int q, int l, int r, int ql, int qr)
 77 {
 78     if(qr < l || ql > r) return;
 79     if(ql <= l && qr >= r && maxv[q] - minv[q] <= 1LL)
 80     {
 81         if(maxv[q] == minv[q] || (ll)sqrt(maxv[q]) == (ll)sqrt(minv[q]))
 82         {
 83             maxv[q] = minv[q] = sqrt(minv[q]);
 84             cover[q] = maxv[q];
 85             lazy[q] = 0;
 86             sum[q] = (ll)(r - l + 1) * maxv[q];
 87         }
 88         else
 89         {
 90             lazy[q] += -1LL * (minv[q] - (ll)sqrt(minv[q]));
 91             sum[q] -= (ll)(r - l + 1) * (minv[q] - (ll)sqrt(minv[q]));
 92             minv[q] = sqrt(minv[q]);
 93             maxv[q] = minv[q] + 1;
 94         }
 95         return;
 96     }
 97     push_down(q);
 98     change(lson, l, mid, ql, qr);
 99     change(rson, mid + 1, r, ql, qr);
100     push_up(q);
101 }
102 ll query(int q, int l, int r, int ql, int qr)
103 {
104     if(qr < l || ql > r) return 0;
105     if(ql <= l && qr >= r)
106     {
107         return sum[q];
108     }
109     push_down(q);
110     ll ret = 0;
111     ret += query(lson, l, mid, ql, qr);
112     ret += query(rson, mid + 1, r, ql, qr);
113     return ret;
114 }
115 int main()
116 {
117     int T; scanf("%d", &T);
118     while(T--)
119     {
120         int n, m; scanf("%d %d", &n, &m);
121         for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
122         build(1, 1, n);
123         for(int i = 1; i <= m; i++)
124         {
125             int type, l, r, x;
126             scanf("%d", &type);
127             if(type == 1)
128             {
129                 scanf("%d %d %d", &l, &r, &x);
130                 change(1, 1, n, l, r, x);
131             }
132             else if(type == 2)
133             {
134                 scanf("%d %d", &l, &r);
135                 change(1, 1, n, l, r);
136             }
137             else if(type == 3)
138             {
139                 scanf("%d %d", &l, &r);
140                 printf("%lld
", query(1, 1, n, l, r));
141             }
142         }
143     }
144     return 0;
145 }

 

以上是关于线段树中区间加减和区间覆盖的双标记问题的主要内容,如果未能解决你的问题,请参考以下文章

值得一做》关于双标记线段树两三事BZOJ 1798 (NORMAL-)

数据结构——线段树

bzoj 维护序列seq(双标记线段树)

楼房重建

2019.7.26 T1 树剖+双标记

Codeforces Round #425 (Div. 2) D 树链剖分 + 树状数组维护区间