【bzoj4695】最假女选手 线段树区间最值操作
题目描述
给定一个长度为 N 序列,编号从 1 到 N 。要求支持下面几种操作:
1.给一个区间[L,R] 加上一个数x
2.把一个区间[L,R] 里小于x 的数变成x
3.把一个区间[L,R] 里大于x 的数变成x
4.求区间[L,R] 的和
5.求区间[L,R] 的最大值
6.求区间[L,R] 的最小值
输入
第一行一个整数 N 表示序列长度。
第二行 N 个整数 Ai 表示初始序列。
第三行一个整数 M 表示操作个数。
接下来 M 行,每行三或四个整数,第一个整数 Tp 表示操作类型,接下来 L,R,X 或 L,R 表述操作数。
1<=tp<=6,N,M<=5*10^5,|Ai|<=10^8
Tp=1时,|x|<=1000
Tp=2或3时,|x|<=10^8
输出
对于每个4,5,6类型的操作输出一行一个整数表示答案。
样例输入
2
1 2
2
2 1 2 2
4 1 2
样例输出
4
题解
线段树区间最值操作
维护区间最小值、最小值个数、严格次小值、最大值、最大值个数、严格次大值、区间和、区间加和标记即可。。。
还要注意,修改区间最小值时要注意其对最大值、严格次大值是否有影响,修改区间最大值时要注意其对最小值、严格次小值的影响。
想想都觉得麻烦。。。
时间复杂度 $O(n\log^2n)$
注意本题略微卡常,不能全用long long,只有区间和使用long long维护。
#include <cstdio> #include <algorithm> #define N 2000010 #define lson l , mid , x << 1 #define rson mid + 1 , r , x << 1 | 1 using namespace std; typedef long long ll; const int inf = 1 << 30; int mx[N] , cx[N] , sx[N] , mn[N] , cn[N] , sn[N] , add[N]; ll sum[N]; inline void pushup(int x) { int ls = x << 1 , rs = x << 1 | 1; sum[x] = sum[ls] + sum[rs]; if(mx[ls] > mx[rs]) mx[x] = mx[ls] , cx[x] = cx[ls] , sx[x] = max(sx[ls] , mx[rs]); if(mx[ls] < mx[rs]) mx[x] = mx[rs] , cx[x] = cx[rs] , sx[x] = max(mx[ls] , sx[rs]); if(mx[ls] == mx[rs]) mx[x] = mx[ls] , cx[x] = cx[ls] + cx[rs] , sx[x] = max(sx[ls] , sx[rs]); if(mn[ls] < mn[rs]) mn[x] = mn[ls] , cn[x] = cn[ls] , sn[x] = min(sn[ls] , mn[rs]); if(mn[ls] > mn[rs]) mn[x] = mn[rs] , cn[x] = cn[rs] , sn[x] = min(mn[ls] , sn[rs]); if(mn[ls] == mn[rs]) mn[x] = mn[ls] , cn[x] = cn[ls] + cn[rs] , sn[x] = min(sn[ls] , sn[rs]); } inline void pushdown(int l , int r , int x) { int ls = x << 1 , rs = x << 1 | 1; if(add[x]) { int mid = (l + r) >> 1; mx[ls] += add[x] , sx[ls] += add[x] , mn[ls] += add[x] , sn[ls] += add[x] , sum[ls] += (mid - l + 1) * add[x] , add[ls] += add[x]; mx[rs] += add[x] , sx[rs] += add[x] , mn[rs] += add[x] , sn[rs] += add[x] , sum[rs] += (r - mid) * add[x] , add[rs] += add[x]; add[x] = 0; } if(mx[ls] > mx[x]) { if(mn[ls] == mx[ls]) mn[ls] = mx[x]; if(sn[ls] == mx[ls]) sn[ls] = mx[x]; sum[ls] += 1ll * (mx[x] - mx[ls]) * cx[ls] , mx[ls] = mx[x]; } if(mx[rs] > mx[x]) { if(mn[rs] == mx[rs]) mn[rs] = mx[x]; if(sn[rs] == mx[rs]) sn[rs] = mx[x]; sum[rs] += 1ll * (mx[x] - mx[rs]) * cx[rs] , mx[rs] = mx[x]; } if(mn[ls] < mn[x]) { if(mx[ls] == mn[ls]) mx[ls] = mn[x]; if(sx[ls] == mn[ls]) sx[ls] = mn[x]; sum[ls] += 1ll * (mn[x] - mn[ls]) * cn[ls] , mn[ls] = mn[x]; } if(mn[rs] < mn[x]) { if(mx[rs] == mn[rs]) mx[rs] = mn[x]; if(sx[rs] == mn[rs]) sx[rs] = mn[x]; sum[rs] += 1ll * (mn[x] - mn[rs]) * cn[rs] , mn[rs] = mn[x]; } } void build(int l , int r , int x) { if(l == r) { scanf("%lld" , &sum[x]) , mx[x] = mn[x] = sum[x] , cx[x] = cn[x] = 1 , sx[x] = -inf , sn[x] = inf; return; } int mid = (l + r) >> 1; build(lson) , build(rson); pushup(x); } void vadd(int b , int e , int a , int l , int r , int x) { if(b <= l && r <= e) { mx[x] += a , sx[x] += a , mn[x] += a , sn[x] += a , sum[x] += 1ll * (r - l + 1) * a , add[x] += a; return; } pushdown(l , r , x); int mid = (l + r) >> 1; if(b <= mid) vadd(b , e , a , lson); if(e > mid) vadd(b , e , a , rson); pushup(x); } void vmax(int b , int e , int a , int l , int r , int x) { if(mn[x] >= a) return; if(b <= l && r <= e && sn[x] > a) { if(mx[x] == mn[x]) mx[x] = a; if(sx[x] == mn[x]) sx[x] = a; sum[x] += 1ll * (a - mn[x]) * cn[x] , mn[x] = a; return; } pushdown(l , r , x); int mid = (l + r) >> 1; if(b <= mid) vmax(b , e , a , lson); if(e > mid) vmax(b , e , a , rson); pushup(x); } void vmin(int b , int e , int a , int l , int r , int x) { if(mx[x] <= a) return; if(b <= l && r <= e && sx[x] < a) { if(mn[x] == mx[x]) mn[x] = a; if(sn[x] == mx[x]) sn[x] = a; sum[x] += 1ll * (a - mx[x]) * cx[x] , mx[x] = a; return; } pushdown(l , r , x); int mid = (l + r) >> 1; if(b <= mid) vmin(b , e , a , lson); if(e > mid) vmin(b , e , a , rson); pushup(x); } ll qsum(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return sum[x]; pushdown(l , r , x); int mid = (l + r) >> 1; ll ans = 0; if(b <= mid) ans += qsum(b , e , lson); if(e > mid) ans += qsum(b , e , rson); return ans; } int qmax(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return mx[x]; pushdown(l , r , x); int mid = (l + r) >> 1 , ans = -inf; if(b <= mid) ans = max(ans , qmax(b , e , lson)); if(e > mid) ans = max(ans , qmax(b , e , rson)); return ans; } int qmin(int b , int e , int l , int r , int x) { if(b <= l && r <= e) return mn[x]; pushdown(l , r , x); int mid = (l + r) >> 1 , ans = inf; if(b <= mid) ans = min(ans , qmin(b , e , lson)); if(e > mid) ans = min(ans , qmin(b , e , rson)); return ans; } int main() { int n , m , opt , x , y , z; scanf("%d" , &n); build(1 , n , 1); scanf("%d" , &m); while(m -- ) { scanf("%d%d%d" , &opt , &x , &y); if(opt == 1) scanf("%d" , &z) , vadd(x , y , z , 1 , n , 1); if(opt == 2) scanf("%d" , &z) , vmax(x , y , z , 1 , n , 1); if(opt == 3) scanf("%d" , &z) , vmin(x , y , z , 1 , n , 1); if(opt == 4) printf("%lld\n" , qsum(x , y , 1 , n , 1)); if(opt == 5) printf("%d\n" , qmax(x , y , 1 , n , 1)); if(opt == 6) printf("%d\n" , qmin(x , y , 1 , n , 1)); } return 0; }