2018宁夏邀请赛 L. Continuous Intervals

转化一下询问即为区间$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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Mrzdtz220/p/11673240.html