3e5那个点t了,怀疑是分治写假了,求带师指导一下
做法是预处理每个数的下一个出现位置,用线段树查询下一个出现位置的最小值判断是否合法
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define re register
using namespace std;
const int N=3e5+10,INF=1e9+1;
int n,a[N];
int t[N<<2];
int pre[N],nxt[N];
inline void up(int x)
{
t[x]=min(t[x<<1],t[x<<1|1]);
}
void build(int x,int l,int r)
{
if(l==r)
{
t[x]=nxt[l];
return ;
}
int mid=l+r>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
up(x);
}
int ask(int x,int l,int r,int ql,int qr)
{
if(l>=ql&&r<=qr) return t[x];
int mid=l+r>>1,ret=INF;
if(ql<=mid) ret=min(ret,ask(x<<1,l,mid,ql,qr));
if(mid<qr) ret=min(ret,ask(x<<1|1,mid+1,r,ql,qr));
return ret;
}
int ans;
void solve(int l,int r)
{
if(l>r) return ;
if(l==r)
{
ans+=(a[l]==1);
return ;
}
int mid=l;
for(re int i=l+1;i<=r;++i) mid= a[i]>a[mid] ? i : mid;
if(mid<=(l+r>>1))
{
for(re int i=mid;i>=l;--i)
{
if(mid-i+1>a[mid]) break ;
if(i+a[mid]-1>r) continue ;
ans+= ask(1,1,n,i,i+a[mid]-1)>i+a[mid]-1 ;
// cout<<mid<<" "<<ask(1,1,n,i,i+a[mid]-1)<<"\n";
}
}
else
{
for(re int i=mid;i<=r;++i)
{
if(i-mid>a[mid]) break ;
if(i-a[mid]+1<l) continue ;
ans+= ask(1,1,n,i-a[mid]+1,i)>i ;
}
}
// cout<<mid<<" "<<ans<<"\n";
solve(l,mid-1),solve(mid+1,r);
}
inline int read(){char cr=getchar();int x_=0,fui=1;while(cr<48){if(cr=='-')fui=-1;cr=getchar();}while(cr>47)x_=(x_*10)+(cr^48),cr=getchar();return x_*fui;}
inline void mwrite(int aq){if(aq>9)mwrite(aq/10);putchar((aq%10)|48);}
inline void write(int af,char cr){mwrite(af<0?(putchar('-'),af=-af):af);putchar(cr);}
signed main()
{
n=read();
for(re int i=1;i<=n;++i) a[i]=read(),nxt[i]=INF;
for(re int i=1;i<=n;++i)
{
// if(!pre[a[i]]) pre[a[i]]=i;
if(pre[a[i]]) nxt[pre[a[i]]]=i;
pre[a[i]]=i;
}
build(1,1,n);
solve(1,n);
write(ans,' ');
return 0;
}