题解:AT_abc397_f [ABC397F] Variety Split Hard
RainRecall · · 题解
首先这种给你一个序列让你求什么东西的问题肯定要先枚举一个什么东西,于是设当前枚举到了
据此,我们可以设
设
然后,我们只需要每次将答案与
于是我们发现需要对
-
区间加。
-
区间最大值。
采用线段树即可解决,时间复杂度
#include<bits/stdc++.h>
#define N 500005
using namespace std;
int n,a[N],g[N],maxn[N*4],z[N*4],vis[N],lst[N],ans;
set<int>s;
void pushup(int x){
maxn[x]=max(maxn[x*2],maxn[x*2+1]);
}
void pushdown(int x){
if(z[x]){
maxn[x*2]+=z[x];maxn[x*2+1]+=z[x];
z[x*2]+=z[x];z[x*2+1]+=z[x];z[x]=0;
}
}
void update(int x,int l,int r,int ql,int qr,int v){
if(ql>qr)return;
if(ql<=l&&r<=qr){
maxn[x]+=v;z[x]+=v;return;
}
int mid=(l+r)>>1;pushdown(x);
if(ql<=mid)update(x*2,l,mid,ql,qr,v);
if(qr>mid)update(x*2+1,mid+1,r,ql,qr,v);
pushup(x);
}
int query(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return maxn[x];
int mid=(l+r)>>1,ans=0;pushdown(x);
if(ql<=mid)ans=max(ans,query(x*2,l,mid,ql,qr));
if(qr>mid)ans=max(ans,query(x*2+1,mid+1,r,ql,qr));
return ans;
}
int main(){
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=n;i>=1;--i)s.insert(a[i]),g[i]=s.size();
for(int i=1;i<=n;++i){
lst[i]=vis[a[i]];
vis[a[i]]=i;
}
int sum0=0;
for(int i=1;i<n;++i){
if(!lst[i])++sum0;
update(1,1,n,i,i,sum0);update(1,1,n,max(lst[i],1),i-1,1);
// for(int j=1;j<=n;++j)cout<<query(1,1,n,j,j)<<" ";cout<<'\n';
if(i!=1)ans=max(ans,query(1,1,n,1,i-1)+g[i+1]);
}
cout<<ans;
return 0;
}