题解:AT_abc470_g [ABC470G] ΣШX
原题大战。
题意:求所有区间的
经典结论就是
考虑移动左端点会发生什么。记
具体分析,若一个位置原本的
#include<bits/stdc++.h>
#define int long long
#define mid (l+r>>1)
using namespace std;
const int N=3e5+5;
long long ans;
int n,a[N],mex[N],mp[N],nxt[N],pos[N],tr[N<<2],mx[N<<2],tag[N<<2];
void pushup(int u){tr[u]=tr[u<<1]+tr[u<<1|1],mx[u]=max(mx[u<<1],mx[u<<1|1]);}
void pushdown(int u,int l,int r){if(~tag[u]) tag[u<<1]=tag[u<<1|1]=tag[u],tr[u<<1]=tag[u]*(mid-l+1),tr[u<<1|1]=tag[u]*(r-mid),mx[u<<1]=mx[u<<1|1]=tag[u],tag[u]=-1;}
void build(int u,int l,int r){tag[u]=-1;if(l==r){mx[u]=tr[u]=mex[l];return;}build(u<<1,l,mid),build(u<<1|1,mid+1,r);pushup(u);}
int query(int u,int l,int r,int L,int R){
if(L<=l&&r<=R) return tr[u];pushdown(u,l,r);int res=0;
if(L<=mid) res+=query(u<<1,l,mid,L,R);
if(mid<R) res+=query(u<<1|1,mid+1,r,L,R);
return res;
}int find(int u,int l,int r,int L,int R,int v){
if(l>R||r<L||mx[u]<=v) return -1;
if(l==r) return l;pushdown(u,l,r);
int res=find(u<<1,l,mid,L,R,v);
return ~res?res:find(u<<1|1,mid+1,r,L,R,v);
}void modify(int u,int l,int r,int L,int R,int v){
if(L<=l&&r<=R){mx[u]=v,tr[u]=v*(r-l+1),tag[u]=v;return;}pushdown(u,l,r);
if(L<=mid) modify(u<<1,l,mid,L,R,v);
if(mid<R) modify(u<<1|1,mid+1,r,L,R,v);
pushup(u);
}signed main(){
cin>>n,pos[0]=pos[n+1]=n+1;
for(int i=1;i<=n;i++) cin>>a[i],pos[i]=n+1;
for(int i=1,ans=0;i<=n;i++){mp[a[i]]++;while(mp[ans]) ans++;mex[i]=ans;}
build(1,1,n);
for(int i=n;i;i--) nxt[i]=pos[a[i]],pos[a[i]]=i;
for(int i=1;i<=n;i++){
ans+=query(1,1,n,i,n);if(i==n) break;
if(i+1<=nxt[i]-1){
int p=find(1,1,n,i+1,nxt[i]-1,a[i]);
if(p!=-1) modify(1,1,n,p,nxt[i]-1,a[i]);
}
}return cout<<ans,0;
}