zoukankan      html  css  js  c++  java
  • 【CF997E】Good Subsegments (线段树+单调栈)

    Description

    原题链接
    给你一个长度为(n)的排列(~P),定义一段子区间是好的,当且仅当这个子区间内的值构成了连续的一段。例如对于排列({1,3,2 })([1, 1], [2, 2], [3, 3], [2, 3], [1, 3])是好的区间。
    (q)次询问,每次询问(L,R), 求有多少(L leq l leq r leq R),满足([l, r])是好的区间。(1 leq n, q leq 1.2 imes 10 ^ 5).

    Solution

    可以发现,区间([l, r])是好的,当且仅当(~(Max_{i = l}^{r} - Min_{i = l} ^ {r}) - (r - l) = 0).
    考虑维护一段区间上式的最小值(以下的最小值都指上式最小值),每一个最小值为(0)的位置都可以和当前的(r)组成一个好的区间。不难发现,一个右端点能产生的贡献为它左边的点的最小值为(0)的个数,于是可以在线段树上维护最小值和最小值个数,以及每个最小值为(0)的位置产生的贡献。
    由于右边新加的点会对已有的点产生影响,考虑离线询问,按右端点排序,用两个单调栈分别维护当前(Min)(Max)。右端点右移时,势必会使整个区间的最小值减一,也势必会使其未右移前的右端点对答案产生一轮贡献,每次处理右端点等于当前枚举点的答案。时间复杂度(O(n log n)).

    Code

    #include <bits/stdc++.h>
    
    #define For(i, j, k) for (int i = j; i <= k; ++ i)
    #define Forr(i, j, k) for (int i = j; i >= k; -- i)
    
    using namespace std;
    
    typedef long long ll;
    
    inline int read() {
    	int x = 0, p = 1; char c = getchar();
    	for (; !isdigit(c); c = getchar()) if (c == '-') p = -1;
    	for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    	return x * p;
    }
    
    inline void File() {
    	freopen("CF997E.in", "r", stdin);
    	freopen("CF997E.out", "w", stdout);
    }
    
    const int N = 1.2e5 + 10;
    int n, q, a[N], s1[N], t1, s2[N], t2, tt = 1; ll ans[N];
    
    struct Query {
    	int id, l, r;
    	bool operator < (const Query &rhs) const { return r < rhs.r; }
    } Q[N];
    
    namespace Segment_Tree {
    #define lc (rt << 1)
    #define rc (rt << 1 | 1)
    #define mid (l + r >> 1)
    
    	const int MAXN = N << 2;
    	int mn[MAXN], tag[MAXN], t[MAXN]; ll sum[MAXN], tg[MAXN];
    	
    	inline void pushdown(int rt) {
    		if (tag[rt]) {
    			mn[lc] += tag[rt], mn[rc] += tag[rt];
    			tag[lc] += tag[rt], tag[rc] += tag[rt];
    			tag[rt] = 0;
    		}
    
    		if (tg[rt]) {
    			if (mn[lc] == mn[rt]) sum[lc] += 1ll * t[lc] * tg[rt], tg[lc] += tg[rt];
    			if (mn[rc] == mn[rt]) sum[rc] += 1ll * t[rc] * tg[rt], tg[rc] += tg[rt];
    			tg[rt] = 0;
    		}
    	}
    
    	inline void pushup(int rt) {
    		t[rt] = 0, mn[rt] = min(mn[lc], mn[rc]);
    		
    		t[rt] = mn[rt] == mn[lc] ? t[rt] + t[lc] : t[rt];
    		t[rt] = mn[rt] == mn[rc] ? t[rt] + t[rc] : t[rt];
    
    		sum[rt] = sum[lc] + sum[rc];
    	}
    
    	inline void Build(int rt, int l, int r) {
    		mn[rt] = l, t[rt] = 1;
    		if (l ^ r) Build(lc, l, mid), Build(rc, mid + 1, r);
    	}
    
    	inline void update(int rt, int l, int r, int L, int R, int v) {
    		if (L <= l && r <= R) { mn[rt] += v, tag[rt] += v; return ; }
    		pushdown(rt); if (L <= mid) update(lc, l, mid, L, R, v);
    		if (R > mid) update(rc, mid + 1, r, L, R, v); pushup(rt);
    	}	
    
    	inline ll query(int rt, int l, int r, int L, int R) {
    		if (L <= l && r <= R) return sum[rt]; pushdown(rt);
    		if (R <= mid) return query(lc, l, mid, L, R);
    		if (L > mid) return query(rc, mid + 1, r, L, R);
    		return query(lc, l, mid, L, R) + query(rc, mid + 1, r, L, R);
    	}
    
    #undef lc
    #undef rc
    #undef mid
    }
    
    int main() {
    	File();
    
    	using namespace Segment_Tree;
    
    	n = read(); For(i, 1, n) a[i] = read();
    	q = read(); For(i, 1, q) Q[i].l = read(), Q[i].r = read(), Q[i].id = i;
    
    	sort(Q + 1, Q + 1 + q);
    
    	Build(1, 1, n);
    
    	For(nr, 1, n) {
    
    		mn[1] -= 1, tag[1] -= 1;
    
    		for (; t1 && a[s1[t1]] < a[nr]; -- t1)
    			update(1, 1, n, s1[t1 - 1] + 1, s1[t1], a[nr] - a[s1[t1]]);
    		s1[++ t1] = nr;
    		
    		for (; t2 && a[s2[t2]] > a[nr]; -- t2)
    			update(1, 1, n, s2[t2 - 1] + 1, s2[t2], a[s2[t2]] - a[nr]);
    		s2[++ t2] = nr;
    
    		sum[1] += t[1], tg[1] += 1;
    
    		for (; tt <= q && Q[tt].r == nr; ++ tt)
    			ans[Q[tt].id] = query(1, 1, n, Q[tt].l, nr);
    	}
    
    	For(i, 1, q) printf("%lld
    ", ans[i]);
    
    	return 0;
    }
    
    
  • 相关阅读:
    springboot与docker
    Docker入门笔记(Centos7)
    记录VUE-CLI项目创建及初始化相关
    centos下安装mysql5.6
    GitLab权限介绍
    属性文件操作之Properties与ResourceBundle
    Shell入门基础
    JavaScript基础的记录
    Java基本排序算法
    解读闭包,这次从ECMAScript词法环境,执行上下文说起
  • 原文地址:https://www.cnblogs.com/LSTete/p/9757600.html
Copyright © 2011-2022 走看看