线段树中区间加减和区间覆盖的双标记问题
Posted wangwangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树中区间加减和区间覆盖的双标记问题相关的知识,希望对你有一定的参考价值。
吉老师真厉害。
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 }
以上是关于线段树中区间加减和区间覆盖的双标记问题的主要内容,如果未能解决你的问题,请参考以下文章