传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4695
【题解】
SegmentTree beats!(见jiry_2论文/营员交流)
考虑只有对p取max,区间加,查min/和怎么做。
有一道类似的题,是取min,见hdu5306.
按照segmentbeats这套理论,我们要维护最小值,最小值出现个数,次小值即可。
每次区间对$p$取max,如果当前节点满足$min < p < sec$,那么打区间max标记,而且我们也可以很方便算出每个的改变量。
标记下传的话考虑对于$x$的儿子,显然要么满足$p < min$,要么满足$min < p < sec$,直接维护即可。
这里的标记我们不需要开一个tag存,我们只要判断是否满足$min < p < sec$就知道是否下传标记了。
【考虑同时维护min/max的情况】
按照segmentbeats这套理论,我们要维护最小值,最小值出现个数,次小值;最大值,最大值出现个数,次大值即可。
对区间取min操作和上面说的取max操作类似,我们着重讨论标记下传问题。
这里涉及到标记的叠加,稍加讨论下我们发现,只要判断$min < min_x < secmin$就知道是否要把$min_x$传给儿子;同理判断$secmax < max_x < max$就知道是否要把$max_x$传给儿子。
这里还涉及到一个问题:标记下传的先后顺序。
考虑什么时候标记存在影响:因为标记都是对最大值和次大值,最小值和次小值之间的区间打的,其他都是暴力维护,所以只对区间长度小于等于2的情况产生影响。
稍加讨论我们发现,先传和后传是没有影响的。
e.g. 区间 = $[3, 6]$
父区间有标记:对于4取max,对于5取min
那么显然没有影响,正常做即可。
父区间有标记:对于5取max,对于4取min。
我们发现,对于5取max的情况,父区间序列一定变成了$[5, ...]$,这时候再对4取min,不符合标记的性质了,所以不存在这种情况。
复杂度:$O(nlog^2n)$,跑的和$O(nlogn)$差不多。
# include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 5e5 + 10, SN = 1048576 + 5; const int mod = 1e9+7, inf = 1e9; inline int getint() { int x = 0, f = 1; char ch = getchar(); while(!isdigit(ch)) { if(ch == '-') f = 0; ch = getchar(); } while(isdigit(ch)) { x = (x<<3) + (x<<1) + ch - '0'; ch = getchar(); } return f ? x : -x; } int n, a[N]; struct node { int p, t, se; node () {} node (int p, int t, int se) : p(p), t(t), se(se) {} inline friend node combineMax(node a, node b) { node c; if(a.p < b.p) { c.p = b.p; c.t = b.t; c.se = max(a.p, b.se); } else if(a.p > b.p) { c.p = a.p; c.t = a.t; c.se = max(a.se, b.p); } else { c.p = a.p; c.t = a.t + b.t; c.se = max(a.se, b.se); } return c; } inline friend node combineMin(node a, node b) { node c; if(a.p > b.p) { c.p = b.p; c.t = b.t; c.se = min(a.p, b.se); } else if(a.p < b.p) { c.p = a.p; c.t = a.t; c.se = min(a.se, b.p); } else { c.p = a.p; c.t = a.t + b.t; c.se = min(a.se, b.se); } return c; } inline friend node operator + (node a, int p) { return node(a.p + p, a.t, a.se + p); } }; struct SMTbeats { node mx[SN], mi[SN]; int tag[SN]; ll s[SN]; # define ls (x<<1) # define rs (x<<1|1) inline void up(int x) { mx[x] = combineMax(mx[ls], mx[rs]); mi[x] = combineMin(mi[ls], mi[rs]); s[x] = s[ls] + s[rs]; } // a = max(a, t) inline void pushmax(int x, int l, int r, int p) { s[x] += 1ll * mi[x].t * (p - mi[x].p); mi[x].p = p; mx[x].p = max(mx[x].p, p); if(mi[x].p == mx[x].p) { mi[x].se = inf, mx[x].se = -inf; mi[x].t = mx[x].t = r-l+1; s[x] = 1ll * mi[x].p * (r-l+1); } else mx[x].se = max(mx[x].se, p); } // a = min(a, t) inline void pushmin(int x, int l, int r, int p) { s[x] += 1ll * mx[x].t * (p - mx[x].p); mx[x].p = p; mi[x].p = min(mi[x].p, p); if(mi[x].p == mx[x].p) { mi[x].se = inf, mx[x].se = -inf; mi[x].t = mx[x].t = r-l+1; s[x] = 1ll * mi[x].p * (r-l+1); } else mi[x].se = min(mi[x].se, p); } inline void pushtag(int x, int l, int r, int p) { tag[x] += p; s[x] += 1ll * (r-l+1) * p; mx[x] = mx[x] + p, mi[x] = mi[x] + p; } inline void down(int x, int l, int r) { int mid = l+r>>1; if(tag[x]) { pushtag(ls, l, mid, tag[x]); pushtag(rs, mid+1, r, tag[x]); tag[x] = 0; } if(mx[ls].p > mx[x].p && mx[ls].se < mx[x].p) pushmin(ls, l, mid, mx[x].p); if(mx[rs].p > mx[x].p && mx[rs].se < mx[x].p) pushmin(rs, mid+1, r, mx[x].p); if(mi[ls].p < mi[x].p && mi[ls].se > mi[x].p) pushmax(ls, l, mid, mi[x].p); if(mi[rs].p < mi[x].p && mi[rs].se > mi[x].p) pushmax(rs, mid+1, r, mi[x].p); } inline void build(int x, int l, int r) { tag[x] = 0; if(l == r) { mx[x].p = mi[x].p = s[x] = a[l], mx[x].t = mi[x].t = 1, mx[x].se = -inf, mi[x].se = inf; return ; } int mid = l+r>>1; build(ls, l, mid); build(rs, mid+1, r); up(x); } inline void edt(int x, int l, int r, int L, int R, int p) { if(L <= l && r <= R) { pushtag(x, l, r, p); return ; } down(x, l, r); int mid = l+r>>1; if(L <= mid) edt(ls, l, mid, L, R, p); if(R > mid) edt(rs, mid+1, r, L, R, p); up(x); } inline void edtmin(int x, int l, int r, int L, int R, int p) { if(mx[x].p <= p) return ; if(L <= l && r <= R && mx[x].se < p) { pushmin(x, l, r, p); return ; } down(x, l, r); int mid = l+r>>1; if(L <= mid) edtmin(ls, l, mid, L, R, p); if(R > mid) edtmin(rs, mid+1, r, L, R, p); up(x); } inline void edtmax(int x, int l, int r, int L, int R, int p) { if(mi[x].p >= p) return ; if(L <= l && r <= R && mi[x].se > p) { pushmax(x, l, r, p); return ; } down(x, l, r); int mid = l+r>>1; if(L <= mid) edtmax(ls, l, mid, L, R, p); if(R > mid) edtmax(rs, mid+1, r, L, R, p); up(x); } inline int gmax(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return mx[x].p; down(x, l, r); int mid = l+r>>1, ret = -inf; if(L <= mid) ret = max(ret, gmax(ls, l, mid, L, R)); if(R > mid) ret = max(ret, gmax(rs, mid+1, r, L, R)); return ret; } inline int gmin(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return mi[x].p; down(x, l, r); int mid = l+r>>1, ret = inf; if(L <= mid) ret = min(ret, gmin(ls, l, mid, L, R)); if(R > mid) ret = min(ret, gmin(rs, mid+1, r, L, R)); return ret; } inline ll gsum(int x, int l, int r, int L, int R) { if(L <= l && r <= R) return s[x]; down(x, l, r); int mid = l+r>>1; ll ret = 0; if(L <= mid) ret += gsum(ls, l, mid, L, R); if(R > mid) ret += gsum(rs, mid+1, r, L, R); return ret; } inline void debug(int x, int l, int r) { printf("%d %d %d [%d %d %d] [%d %d %d] %I64d ", x, l, r, mx[x].p, mx[x].t, mx[x].se, mi[x].p, mi[x].t, mi[x].se, s[x]); if (l == r) return ; int mid = l+r>>1; debug(ls, l, mid); debug(rs, mid+1, r); } # undef ls # undef rs }T; int main() { n = getint(); for (int i=1; i<=n; ++i) a[i] = getint(); T.build(1, 1, n); int Q, op, l, r, x; cin >> Q; while(Q--) { // T.debug(1, 1, n); op = getint(), l = getint(), r = getint(); if(op == 1) { x = getint(); T.edt(1, 1, n, l, r, x); } else if(op == 2) { x = getint(); T.edtmax(1, 1, n, l, r, x); } else if(op == 3) { x = getint(); T.edtmin(1, 1, n, l, r, x); } else if(op == 4) printf("%lld ", T.gsum(1, 1, n, l, r)); else if(op == 5) printf("%d ", T.gmax(1, 1, n, l, r)); else printf("%d ", T.gmin(1, 1, n, l, r)); } return 0; }