题意
-
给定一个序列,定义一个好的区间:
- 对于区间里出现的数(a_i)恰好出现(a_i)次
- 区间里的数的值域连续
-
求好的区间数量
考虑以某个点(i)结束的好的区间的最后起始位置,然后向前拓展,发现最多拓展(n)次,并且每次拓展一定会将值域向小/大拓展至少1,考虑到从(1)一直加到(sqrt n)就会大于(n),所以说好的区间不会超过(nsqrt 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
", as);
return 0;
}