可以从HDU-5306开始练手。
吉司机线段树可以解决什么问题?
譬如说区间操作:对[L, R]区间,使得L ≤ i ≤ R,a[i] = min(a[i], x)。
然后还有区间求和、求max、min这样的操作。
我们可以用O((n + q)log(n))的复杂度来解决这个问题。
只需要存储这样的几个值:
- mx[rt]表示以rt为根的区间的最大值
- md[rt]表示以rt为根的区间的严格次大值
- cnt[rt]表示以rt为根的区间的最大值的个数
- sum[rt]表示以rt为根的区间和的值
- lazy[rt]表示以rt为根的区间,现在的懒标记(记录更新的值,但是不下推)
然后我们可以以这五个数组来用以维护一个吉司机线段树。
操作:
如果mx[rt] ≤ x,那么x就是无效的更改,没用,return;
如果md[rt] ≥ x,我们需要对于左右子树区间进行暴力更改;
剩下的情况就是md[rt] < x < mx[rt],那么此时只需要更改目前子树的mx[rt]值就可以了,当然,我们在这里需要打lazy懒标记,因为我们不下传这个值了。
时间复杂度的证明的关键点,就是在于对于区间的种类数的改变,因为只有暴力更改的时候才会造成高复杂度,但是会发现每次暴力更改,只会让区间的数的种类数减少,而减少的次数肯定是有限的,所以复杂度实际上不是很高。
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <string> 5 #include <cstring> 6 #include <algorithm> 7 #include <limits> 8 #include <vector> 9 #include <stack> 10 #include <queue> 11 #include <set> 12 #include <map> 13 #include <bitset> 14 #include <unordered_map> 15 #include <unordered_set> 16 #define lowbit(x) ( x&(-x) ) 17 #define pi 3.141592653589793 18 #define e 2.718281828459045 19 #define INF 0x3f3f3f3f 20 #define HalF (l + r)>>1 21 #define lsn rt<<1 22 #define rsn rt<<1|1 23 #define Lson lsn, l, mid 24 #define Rson rsn, mid+1, r 25 #define QL Lson, ql, qr 26 #define QR Rson, ql, qr 27 #define myself rt, l, r 28 #define pii pair<int, int> 29 #define MP(a, b) make_pair(a, b) 30 using namespace std; 31 typedef unsigned long long ull; 32 typedef unsigned int uit; 33 typedef long long ll; 34 const int maxN = 1e6 + 7; 35 int N, M; 36 int mx[maxN << 2], md[maxN << 2], cnt[maxN << 2], lazy[maxN << 2]; 37 ll sum[maxN << 2]; 38 void pushup(int rt) 39 { 40 sum[rt] = sum[lsn] + sum[rsn]; 41 if(mx[lsn] == mx[rsn]) 42 { 43 mx[rt] = mx[lsn]; 44 cnt[rt] = cnt[lsn] + cnt[rsn]; 45 md[rt] = max(md[lsn], md[rsn]); 46 } 47 else if(mx[lsn] > mx[rsn]) 48 { 49 mx[rt] = mx[lsn]; 50 cnt[rt] = cnt[lsn]; 51 md[rt] = max(mx[rsn], md[lsn]); 52 } 53 else 54 { 55 mx[rt] = mx[rsn]; 56 cnt[rt] = cnt[rsn]; 57 md[rt] = max(mx[lsn], md[rsn]); 58 } 59 } 60 void build(int rt, int l, int r) 61 { 62 lazy[rt] = -1; 63 if(l == r) { scanf("%d", &mx[rt]); md[rt] = -1; cnt[rt] = 1; sum[rt] = mx[rt]; return; } 64 int mid = HalF; 65 build(Lson); 66 build(Rson); 67 pushup(rt); 68 } 69 void pushdown(int rt) 70 { 71 if(~lazy[rt]) 72 { 73 if(lazy[rt] < mx[lsn]) 74 { 75 sum[lsn] = sum[lsn] - 1LL * cnt[lsn] * (mx[lsn] - lazy[rt]); 76 mx[lsn] = lazy[rt]; 77 lazy[lsn] = lazy[rt]; 78 } 79 if(lazy[rt] < mx[rsn]) 80 { 81 sum[rsn] = sum[rsn] - 1LL * cnt[rsn] * (mx[rsn] - lazy[rt]); 82 mx[rsn] = lazy[rt]; 83 lazy[rsn] = lazy[rt]; 84 } 85 lazy[rt] = -1; 86 } 87 } 88 void update(int rt, int l, int r, int ql, int qr, int val) 89 { 90 if(r < ql || l > qr || val >= mx[rt]) return; 91 pushdown(rt); 92 int mid = HalF; 93 if(md[rt] >= val) 94 { 95 update(QL, val); 96 update(QR, val); 97 pushup(rt); 98 } 99 else 100 { 101 if(ql <= l && qr >= r) 102 { 103 lazy[rt] = val; 104 sum[rt] = sum[rt] - 1LL * cnt[rt] * (mx[rt] - val); 105 mx[rt] = val; 106 } 107 else 108 { 109 pushdown(rt); 110 if(qr <= mid) update(QL, val); 111 else if(ql > mid) update(QR, val); 112 else { update(QL, val); update(QR, val); } 113 pushup(rt); 114 } 115 } 116 } 117 int query_max(int rt, int l, int r, int ql, int qr) 118 { 119 if(ql <= l && qr >= r) return mx[rt]; 120 pushdown(rt); 121 int mid = HalF; 122 if(qr <= mid) return query_max(QL); 123 else if(ql > mid) return query_max(QR); 124 else return max(query_max(QL), query_max(QR)); 125 } 126 ll query_sum(int rt, int l, int r, int ql, int qr) 127 { 128 if(ql <= l && qr >= r) return sum[rt]; 129 pushdown(rt); 130 int mid = HalF; 131 if(qr <= mid) return query_sum(QL); 132 else if(ql > mid) return query_sum(QR); 133 else return query_sum(QL) + query_sum(QR); 134 } 135 int main() 136 { 137 int T; scanf("%d", &T); 138 while(T --) 139 { 140 scanf("%d%d", &N, &M); 141 build(1, 1, N); 142 for(int i=1, op, l, r, x; i<=M; i++) 143 { 144 scanf("%d%d%d", &op, &l, &r); 145 switch (op) 146 { 147 case 0: 148 { 149 scanf("%d", &x); 150 update(1, 1, N, l, r, x); 151 break; 152 } 153 case 1: 154 { 155 printf("%d\n", query_max(1, 1, N, l, r)); 156 break; 157 } 158 default: 159 { 160 printf("%lld\n", query_sum(1, 1, N, l, r)); 161 break; 162 } 163 } 164 } 165 } 166 return 0; 167 } 168 /* 169 1 170 5 2 171 4 3 3 2 2 172 0 2 3 2 173 1 2 5 174 ans:2 175 */