Problem Description
There is a sequence a of length n. We use ai to denote the i-th element in this sequence. You should do the following three types of operations to this sequence.
0 x y t: For every x≤i≤y, we use min(ai,t) to replace the original ai's value.
1 x y: Print the maximum value of ai that x≤i≤y.
2 x y: Print the sum of ai that x≤i≤y.
Input
The first line of the input is a single integer T, indicating the number of testcases.
The first line contains two integers n and m denoting the length of the sequence and the number of operations.
The second line contains n separated integers a1,…,an (∀1≤i≤n,0≤ai<231).
Each of the following m lines represents one operation (1≤x≤y≤n,0≤t<231).
It is guaranteed that T=100, ∑n≤1000000, ∑m≤1000000.
Output
For every operation of type 1 or 2, print one line containing the answer to the corresponding query.
Sample Input
1 5 5 1 2 3 4 5 1 1 5 2 1 5 0 3 5 3 1 1 5 2 1 5
Sample Output
5 15 3 12
Hint
Please use efficient IO method
Author
XJZX
Source
2015 Multi-University Training Contest 2
Recommend
wange2014
题目大意: 三种操作
0 l r t: 使这个区间的每个值变成min(t,a[i])。
1 l r: 输出区间最大值
2 l r: 输出区间和
(1 <= n,m <= 1e6, 0 <= ai,t <= 2^31)
解题思路:1和2操作很简单,0操作很难,一个一个改时间肯定不允许,所以我们可以考虑每次对于0操作的t是否对最大值和区间和有影响。当这个值大于你要修改区间的最大值,就不需要有这个更新操作了啊,对于区间和,如果有影响,我们可以统计一下最大值的个数,通过运算可以直接修改区间和,就没有必要去一个一个修改。所以我们需要记录的变量有:区间最大值,区间和的值,次小值,区间最大值的个数。
对于0操作仅仅有以下三种操作即可:
- t >= 区间最大值, 这时每个值都不用修改,直接返回。
- 区间次大值 < t < 区间最大值,此时只有最大值会变,又已经求得了最大值的个数,所以我们可以直接更新这段的sum和max。
- 其他情况。无法直接对当前情况修改,所以继续搜两个儿子,直到搜到前两种情况为止。
/* @Author: Top_Spirit @Language: C++ */ #include <bits/stdc++.h> using namespace std ; typedef unsigned long long ull ; typedef long long ll ; typedef pair < int, int > P ; const int Maxn = 1e6 + 10 ; const int Mod = 1e9 + 7 ; const int INF = 0x3f3f3f3f ; #define lson ri << 1, l, mid #define rson ri << 1 | 1, mid + 1, r ll sum[Maxn << 2], Max[Maxn << 2], se[Maxn << 2], cnt[Maxn] ; int n, m ; ll ansMax = 0 ; void pushUp(int ri){ sum[ri] = sum[ri << 1] + sum[ri << 1 | 1] ; Max[ri] = max(Max[ri << 1], Max[ri << 1 | 1]) ; if (Max[ri << 1] == Max[ri << 1 | 1]) { se[ri] = max(se[ri << 1], se[ri << 1 |1 ]) ; cnt[ri] = cnt[ri << 1] + cnt[ri << 1 | 1] ; } else { se[ri] = max(se[ri << 1], se[ri << 1 | 1]) ; se[ri] = max(se[ri], min(Max[ri << 1], Max[ri << 1 | 1])) ; cnt[ri] = Max[ri << 1] > Max[ri << 1 | 1] ? cnt[ri << 1] : cnt[ri << 1 | 1] ; } } void Build (int ri, int l, int r){ if (l == r){ cin >> sum[ri] ; Max[ri] = sum[ri] ; se[ri] = -1 ; cnt[ri] = 1 ; return ; } int mid = (l + r) >> 1 ; Build(lson) ; Build(rson) ; pushUp(ri) ; } void pushTag(int ri, int val) { if (val >= Max[ri]) return ; sum[ri] -= cnt[ri] * (Max[ri] - val) ; Max[ri] = val ; } void pushDown(int ri ) { pushTag(ri << 1, Max[ri]) ; pushTag(ri << 1 | 1, Max[ri]) ; } void update(int L, int R, int val, int ri, int l, int r){ if (val >= Max[ri]) return ; if (l >= L && r <= R && val > se[ri]){ pushTag(ri,val) ; return ; } pushDown(ri) ; int mid = (l + r) >> 1 ; if (L <= mid) update (L, R, val, lson) ; if (R > mid) update (L, R, val, rson) ; pushUp(ri) ; } void queryMax(int L, int R, int ri, int l, int r){ if (l >= L && r <= R){ ansMax = max(ansMax, Max[ri]) ; return ; } pushDown(ri) ; int mid = (l + r) >> 1 ; if (L <= mid) queryMax(L, R, lson) ; if (R > mid) queryMax(L, R, rson) ; } ll querySum (int L, int R, int ri, int l, int r){ if (l >= L && r <= R) return sum[ri] ; pushDown(ri) ; ll ans = 0 ; int mid = (l + r) >> 1 ; if (L <= mid) ans += querySum(L, R, lson) ; if (R > mid) ans += querySum(L, R, rson) ; return ans ; } int main (){ ios_base::sync_with_stdio(false) ; cin.tie(0) ; cout.tie(0) ; int T ; cin >> T ; while (T--){ cin >> n >> m ; Build(1, 1, n ) ; // cout << "____++++" << endl ; while (m--){ int op ; cin >> op ; if (op == 0){ int x, y, t ; cin >> x >> y >> t ; update(x, y, t, 1, 1, n) ; } else if (op == 1){ int x, y ; cin >> x >> y ; ansMax = -1 ; queryMax(x, y, 1, 1, n) ; cout << ansMax << endl ; } else { int x, y ; cin >> x >> y ; ll ans = querySum(x, y, 1, 1, n) ; cout << ans << endl ; } } } return 0; }