对于每个点求出开头到该点的最长上升子序列长度==以及该点到结尾的最长上升子序列长度
(该点都强制使用)记为dp1和dp2
于是如果dp1[i]+dp2[i]-1与LIS的长度相等 则该点为2或3否则为1
对于不是1的点如果有别的点与它dp1相同则为2(即可以选该点也可以选别的相同的点)否则为3
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 100010
using namespace std;
int stk[N],a[N],dp1[N],dp2[N],ans[N],wzf[N],len,n;
int read(){
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
int k=ch-48;
while (1){
ch=getchar();
if (ch<'0'||ch>'9') return k;
k=k*10+ch-48;
}
}
int main(){
int n=read();
rep(i,1,n) a[i]=read();
int top=0;
rep(i,1,n){
if (a[i]>stk[top]) stk[++top]=a[i],dp1[i]=top;
else{
int k=top;
while (a[i]<=stk[k-1]) k--;
stk[k]=a[i];
dp1[i]=k;
}
}
rep(i,1,n/2) swap(a[i],a[n-i+1]);
len=top;top=0;stk[0]=N;
rep(i,1,n){
if (a[i]<stk[top]) stk[++top]=a[i],dp2[n-i+1]=top;
else{
int k=top;
while (a[i]>=stk[k-1]) k--;
stk[k]=a[i];
dp2[n-i+1]=k;
}
}
rep(i,1,n) if (dp1[i]+dp2[i]<len+1) ans[i]=1;
top=0;
rep(i,1,n) if (ans[i]!=1){
if (wzf[dp1[i]]==0){
ans[i]=3;
wzf[dp1[i]]=i;
}else ans[wzf[dp1[i]]]=ans[i]=2;
}
rep(i,1,n) printf("%d",ans[i]);
puts("");
}