【LGR-077】洛谷 10 月月赛 I Div.1 && P6854 Tram

题意

  • 给定一个序列,定义一个好的区间:

    1. 对于区间里出现的数\(a_i\)恰好出现\(a_i\)
    2. 区间里的数的值域连续
  • 求好的区间数量

考虑以某个点\(i\)结束的好的区间的最后起始位置,然后向前拓展,发现最多拓展\(n\)次,并且每次拓展一定会将值域向小/大拓展至少1,考虑到从\(1\)一直加到\(\sqrt n\)就会大于\(n\),所以说好的区间不会超过\(n\sqrt n\)级别

那么只需要\(o(1)\)或者\(o(\log n)\)的复杂度内找到一个可行位置再加进答案就行

于是从左往右,每次对当前数维护可行的区间就好

具体的操作是,假设当前数为\(x\)那么找到前\(x\)个的位置,这中间是不能选的,以及前\(x+1\)\(x\)之前的位置也是不能选的

所以就可以线段树,每次将不能选的位置\(+1\),维护区间最小值,然后在线段树上二分即可

#include<bits/stdc++.h>
#define For(i, a, b) for(int i = (a), en = (b); i <= en; ++i)
#define Rof(i, a, b) for(int i = (a), en = (b); i >= en; --i)
#define Tra(u, i) for(int i = hd[u]; ~i; i = e[i].net)
#define cst const
#define LL long long
#define DD double
#define LD long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define eps 1e-12
#define maxn 1000000
using namespace std;

int n, a[maxn + 5], as = 0, pre[maxn + 5], net[maxn + 5], to[maxn + 5], cnt[maxn + 5];
map<int, int> ma;
void chkmn(int &x, int y){if(x > y) x = y;}
void chkmx(int &x, int y){if(x < y) x = y;}
int tr[2][maxn + 5];
void ins(int ty, int x, int y){
	x = maxn - x + 1;
	while(x <= maxn) ty ? chkmx(tr[ty][x], y) : chkmn(tr[ty][x], y), x += x & -x;
}
int que(int ty, int x){
	x = maxn - x + 1; int asi = ty ? 0 : inf;
	while(x) ty ? chkmx(asi, tr[ty][x]) : chkmn(asi, tr[ty][x]), x -= x & -x;
	return asi;
}
struct Node{int mn, lpr;} poi[4 * maxn + 5];
struct Tree{
	#define ls rt << 1
	#define rs rt << 1 | 1
	#define mn(rt) poi[rt].mn
	#define lpr(rt) poi[rt].lpr
	void upd(int rt){mn(rt) = min(mn(ls), mn(rs));}
	void mson(int rt, int x){
		mn(rt) += x;
		lpr(rt) += x;
	}
	void spr(int rt){
		if(!lpr(rt)) return;
		mson(ls, lpr(rt));
		mson(rs, lpr(rt));
		lpr(rt) = 0;
	}
	void mdy(int rt, int nl, int nr, int ql, int qr, int x){
		if(ql > qr) return;
		if(ql <= nl && qr >= nr) return mson(rt, x);
		spr(rt);
		int mid = nl + nr >> 1;
		if(ql <= mid) mdy(ls, nl, mid, ql, qr, x);
		if(qr > mid) mdy(rs, mid + 1, nr, ql, qr, x);
		upd(rt);
	}
	void sol(int rt, int nl, int nr, int ql, int qr){
		if(mn(rt)) return;
		if(nl == nr){
			int mn = que(0, nl), mx = que(1, nl);
			if((mn + mx) * (mx - mn + 1) / 2 == qr - nl + 1) as++;
			return;
		}
		spr(rt);
		int mid = nl + nr >> 1;
		if(ql <= mid) sol(ls, nl, mid, ql, qr);
		if(qr > mid) sol(rs, mid + 1, nr, ql, qr);
	}
	void quee(int rt, int nl, int nr){
		if(nl == nr) return (void)(cout << mn(rt) << " ");
		spr(rt);
		int mid = nl + nr >> 1;
		quee(ls, nl, mid); quee(rs, mid + 1, nr);
	}
} tr1;

template <class T>
void read(T &x){
	char ch;
	bool ok;
	for(ok = 0, ch = getchar(); !isdigit(ch); ch = getchar()) if(ch == '-') ok = 1;
	for(x = 0; isdigit(ch); x = x * 10 + ch - '0', ch = getchar());
	if(ok) x = -x;
}

void mdy(int x, int y){
	if(!x) return;
	if(cnt[x] > a[x]) tr1.mdy(1, 1, n, to[x] + 1, x, y), tr1.mdy(1, 1, n, 1, pre[to[x]], y);
	else if(cnt[x] == a[x]) tr1.mdy(1, 1, n, to[x] + 1, x, y);
	else tr1.mdy(1, 1, n, 1, x, y);
	ins(0, x, a[x]);
	ins(1, x, a[x]);
	//if(x == 2) cout << que(0, x) << endl;
}

int main(){
	//freopen("in", "r", stdin);
	memset(tr[0], inf, sizeof tr[0]);
	read(n);
	For(i, 1, n){
		read(a[i]);
		net[pre[i] = ma[a[i]]] = i;
		ma[a[i]] = i;
		cnt[i] = cnt[pre[i]] + 1;
		if(a[i] == 1) to[i] = i;
		else if(cnt[i] > a[i]) to[i] = net[to[pre[i]]];
		else if(cnt[i] == a[i]) to[i] = to[pre[i]];
		else if(cnt[i] == 1) to[i] = i;
		else to[i] = to[pre[i]];
		mdy(pre[i], -1);
		mdy(i, 1);
		tr1.sol(1, 1, n, 1, i);
		/*tr1.quee(1, 1, n);
		puts("");*/
	}
	printf("%d\n", as);
	return 0;
}
posted @ 2020-10-11 20:44  lprdsb  阅读(200)  评论(1编辑  收藏  举报