转化一下询问即为区间$max - min + 1 = cnt$,其中$cnt$表示区间内数的种类数。
即求有多少区间$max - min - cnt=-1$,注意到任意区间的$max-min-cnt \geq -1$,那么即维护区间$max-min-cnt$的最小值和最小值的个数,再看最小值等不等于$-1$就行了。
那么可以用扫描线扫右端点$r$,线段树维护左端点为$1, 2,\dots,r-1$的区间最小值和最小值的个数。每加入一个数,$r$这里必定为$-1$,所以当前区间最小值的个数就是答案了。
对于区间种类数就$[last[a[i]], i - 1]$多了$1$,那么要减去$1$,因为在式子里$cnt$,前面是负号。
然后最大值最小值就用两个单调栈搞一下就好了。区间加上对应的差值即可。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 1e5 + 7; int top1, top2, a[N], st1[N], st2[N]; map<int, int> pos; struct Seg { #define lp p << 1 #define rp p << 1 | 1 int tree[N << 2], lazy[N << 2], sum[N << 2]; inline void init() { memset(tree, 0, sizeof(tree)); memset(lazy, 0, sizeof(lazy)); memset(sum, 0x3f, sizeof(sum)); } inline void pushdown(int p) { if (lazy[p] == 0) return; lazy[lp] += lazy[p]; lazy[rp] += lazy[p]; sum[lp] += lazy[p]; sum[rp] += lazy[p]; lazy[p] = 0; } inline void pushup(int p) { sum[p] = min(sum[lp], sum[rp]); if (sum[lp] == sum[rp]) tree[p] = tree[lp] + tree[rp]; else if (sum[lp] < sum[rp]) tree[p] = tree[lp]; else tree[p] = tree[rp]; } void update(int p, int l, int r, int pos) { if (l == r) { tree[p] = 1; sum[p] = -1; return; } pushdown(p); int mid = l + r >> 1; if (pos <= mid) update(lp, l, mid, pos); else update(rp, mid + 1, r, pos); pushup(p); } void update(int p, int l, int r, int x, int y, int val) { if (x > y) return; if (x <= l && y >= r) { sum[p] += val; lazy[p] += val; return; } pushdown(p); int mid = l + r >> 1; if (x <= mid) update(lp, l, mid, x, y, val); if (y > mid) update(rp, mid + 1, r, x, y, val); pushup(p); } } seg; inline void init() { top1 = top2 = 0; seg.init(); pos.clear(); } int main() { int T; int kase = 0; scanf("%d", &T); while (T--) { init(); ll ans = 0; int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { seg.update(1, 1, n, i); scanf("%d", &a[i]); while (top1 && a[st1[top1]] <= a[i]) { int p = st1[top1], key = a[st1[top1]]; top1--; seg.update(1, 1, n, st1[top1] + 1, p, a[i] - key); } st1[++top1] = i; while (top2 && a[st2[top2]] >= a[i]) { int p = st2[top2], key = a[st2[top2]]; top2--; seg.update(1, 1, n, st2[top2] + 1, p, key - a[i]); } st2[++top2] = i; int l = pos[a[i]]; seg.update(1, 1, n, l + 1, i - 1, -1); pos[a[i]] = i; ans += seg.tree[1]; } printf("Case #%d: %lld\n", ++kase, ans); } return 0; }
2018宁夏邀请赛 L. Continuous Intervals
原文:https://www.cnblogs.com/Mrzdtz220/p/11673240.html