GMOJ 6808 easy 题解

区间符合条件的充要条件是(Max-Min+1=Cnt)其中(Max,Min,Cnt)分别为区间最大值,最小值,不同的数的个数。

变形后得(Max-Min-Cnt+1=0)

考虑枚举右端点,在线段树上维护左端点(Max-Min-Cnt+1)的最小值。

(Min,Max)可以用单调栈维护,记(last_i)(a_i)上一次出现的位置,那么对于每个左端点(i),([last_i+1, i])(Cnt)(+1)

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn=100000;

class Ele {
    public:
        int v, id;

        static bool cmp(Ele &a, Ele &b) {
            return a.v<b.v || (a.v==b.v && a.id<=b.id);
        }
};

void getLast(int n, int a[], int last[]) {
    static Ele b[maxn+1];
    for (int i=1; i<=n; i++) {
        b[i].v = a[i], b[i].id = i;
    }
    sort(b+1, b+n+1, Ele::cmp);
    for (int i=1; i<=n; i++) {
        last[b[i].id] = b[i].v==b[i-1].v ? b[i-1].id : 0;
    }
}

class SegmentTree {
	public:
		int v[4*maxn+1], cnt[4*maxn+1], mark[4*maxn+1];

        void init(int o, int l, int r) {
            int mid=(l+r)/2;
            cnt[o] = r-l+1;
            if (l!=r) init(o*2, l, mid), init(o*2+1, mid+1, r);
        }

		void pushDown(int o, int l, int r) {
			if (mark[o]) {
				v[o] += mark[o];
				if (l!=r) {
					mark[o*2]+=mark[o];
					mark[o*2+1]+=mark[o];
				}
				mark[o] = 0;
			}
		}

		void add(int o, int l, int r, int tl, int tr, int tv) {
			pushDown(o, l, r);
			if (l==tl && r==tr) {
				mark[o] += tv;
				pushDown(o, l, r);
			} else {
				int mid=(l+r)/2;
				if (tl<=mid) add(o*2, l, mid, tl, min(tr, mid), tv);
				else pushDown(o*2, l, mid);
				if (tr>mid) add(o*2+1, mid+1, r, max(tl, mid+1), tr, tv);
				else pushDown(o*2+1, mid+1, r);
				if (v[o*2]<v[o*2+1]) v[o]=v[o*2], cnt[o]=cnt[o*2];
				else if (v[o*2]>v[o*2+1]) v[o]=v[o*2+1], cnt[o]=cnt[o*2+1];
				else v[o]=v[o*2], cnt[o]=cnt[o*2]+cnt[o*2+1];
			}
		}

        int getZero(int o, int l, int r, int tl, int tr) {
            pushDown(o, l, r);
            if (l==tl && r==tr) return v[o] ? 0 : cnt[o];
            else {
                int mid=(l+r)/2, ret=0;
                if (tl<=mid) ret+=getZero(o*2, l, mid, tl, min(tr, mid));
                if (tr>mid) ret+=getZero(o*2+1, mid+1, r, max(tl, mid+1), tr);
                return ret;
            }
        }
};

int main() {
    freopen("easy.in", "r", stdin);
    freopen("easy.out", "w", stdout);

    static int a[maxn+1], last[maxn+1], minq[maxn+1], maxq[maxn+1];
    int n;
    scanf("%d", &n);
    for (int i=1; i<=n; i++) {
        scanf("%d", a+i);
    }
    getLast(n, a, last);

	static SegmentTree sgt;
    sgt.init(1, 1, n);
	long long ans=0;
	for (int i=1; i<=n; i++) {
        if (last[i]<i-1) sgt.add(1, 1, n, last[i]+1, i-1, -1);

		for (; minq[0] && a[minq[minq[0]]]>=a[i]; minq[0]--) {
			sgt.add(1, 1, n, (minq[0]==1 ? 1 : minq[minq[0]-1]+1), minq[minq[0]], a[minq[minq[0]]]);
		}
		sgt.add(1, 1, n, minq[0] ? minq[minq[0]]+1 : 1, i, -a[i]);
		minq[++minq[0]] = i;

		for (; maxq[0] && a[maxq[maxq[0]]]<=a[i]; maxq[0]--) {
			sgt.add(1, 1, n, (maxq[0]==1 ? 1 : maxq[maxq[0]-1]+1), maxq[maxq[0]], -a[maxq[maxq[0]]]);
		}
		sgt.add(1, 1, n, maxq[0] ? maxq[maxq[0]]+1 : 1, i, a[i]);
		maxq[++maxq[0]] = i;

		ans += sgt.getZero(1, 1, n, 1, i);
	}

	printf("%lld
", ans);

    fclose(stdin);
    fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/BunnyLutts/p/13909782.html