• 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;
    }
    
    
  • 相关阅读:
    邮件发送的存储过程写法
    FormsAuthentication.GetRedirectUrl 方法
    视图性能优化——索引视图
    删除多字段的重复行保留最大最小行
    c#知识点
    sql存储过程exec执行字符串select 的区别
    UVALive5198 UVA512 Spreadsheet Tracking
    UVA129 HDU1627 Krypton Factor
    UVA129 HDU1627 Krypton Factor
    UVA10603 Fill
  • 原文地址:https://www.cnblogs.com/BunnyLutts/p/13909782.html
Copyright © 2020-2023  润新知