https://codeforces.com/contest/1436/problem/E
直接用权值树状数组暴力模拟就好了,想了一年想不出来
树状数组b[i]记录值为i上次出现的位置在哪,getmi求前缀最小位置在哪里
然后枚举右端点,不断地更新最小位置,一开始b[i]初值全部设成n+1
然后考虑直接右端点就是n,每个数字上次出现的位置就是他最后出现的位置
如果对于某个数字i,last[i]!=n && getmi(i-1)>last[i],也就是从末尾到i最后出现的位置,1-i-1每个数字都出现过,但是i没有出现过,那么这一段的mex值就是i,那么vis[i]=true;
接着从后往前更新,每次把i这个数字去掉,也就是右端点从i-1开始,那么就把b[a[i]]更新为pre[i]就行了,然后考虑要不要vis[a[i]]=true
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cnt,tot,cas,ans;
int a[maxl],b[maxl],last[maxl],pre[maxl],nxt[maxl];
bool vis[maxl];
char s[maxl];
inline void prework()
{
scanf("%d",&n);
ans=1;
for(int i=1;i<=n+1;i++)
last[i]=0,pre[i]=n+2;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pre[i]=last[a[i]];
last[a[i]]=i;
}
}
inline void upd(int i,int x)
{
while(i<=n+1)
{
b[i]=min(b[i],x);
i+=i&-i;
}
}
inline int getmi(int i)
{
int ret=n+2;
while(i)
{
ret=min(ret,b[i]);
i-=i&-i;
}
return ret;
}
inline void mainwork()
{
for(int i=1;i<=n;i++)
b[i]=n+1;
for(int i=1;i<=n;i++)
upd(i,last[i]);
for(int i=1;i<=n+1;i++)
if(last[i]!=n && getmi(i-1)>last[i])
vis[i]=true;
for(int i=n;i>=1;i--)
{
upd(a[i],pre[i]);
if(pre[i]!=i-1 && getmi(a[i]-1)>pre[i])
vis[a[i]]=true;
}
ans=1;
while(vis[ans])
ans++;
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}