GMOJ 6808 easy 題解
阿新 • • 發佈:2020-11-01
區間符合條件的充要條件是\(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\n", ans); fclose(stdin); fclose(stdout); return 0; }