题意:
计算 其中mex即为博弈中出现的mex(未出现的最小非负整数)。
分析:
有两种方法,递推有点懵(以后再来补QAQ),就写了线段树
想法是每次求以i为起点的区间的mex值的和,最后累加即为答案。
可以先预处理出1为起点的区间的mex值,用它构造一棵线段树,要有求和和求最大值的操作。
构造好线段树之后,1为起点的区间的mex和已经得到了,就是sum[1]。
接下来求2为起点的,首先第一步要删掉a[1],这里把mex[1]置为0(区间求和不再受影响)。
删掉val=a[1]这个元素对后面的有什么影响呢?易知它不会对下一个出现val(下一个出现val的位置是next[1])之后的位置产生影
响,因为后面的区间已经包含val了(不少它这一个)
然后我们需要求得大于val的最大mex的位置pos,线段树单点查询最大值即可得到。
对于pos到next[1] - 1的元素,所有的mex值都要变成a[i](不难想),成段更新线段树即可。
这样就得到了2为起点的区间的mex和,sum[1]。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
struct node{
ll mex,sum;
bool lazy;
}tree[maxn<<2];
ll a[maxn],tmp[maxn];
void pushdown(int p,int l,int r){
if(!tree[p].lazy) return;
int mid=l+r>>1;
tree[p<<1].sum=tree[p].mex*1ll*(mid-l+1);
tree[p<<1|1].sum=tree[p].mex*1ll*(r-mid);
tree[p<<1].mex=tree[p<<1|1].mex=tree[p].mex;
tree[p<<1].lazy=tree[p<<1|1].lazy=1;
tree[p].lazy=0;
}
void pushup(int p){
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
tree[p].mex=max(tree[p<<1].mex,tree[p<<1|1].mex);
}
void build(int p,int l,int r){
tree[p].lazy=0;
if(l==r){
tree[p].sum=tree[p].mex=tmp[l];
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void update(int tl,int tr,ll val,int l,int r,int p){
if(tl>r||tr<l) return;
if(tl<=l&&r<=tr){
tree[p].sum=(r-l+1)*1ll*val;
tree[p].mex=val;
tree[p].lazy=true;
return;
}
pushdown(p,l,r);
int mid=l+r>>1;
update(tl,tr,val,l,mid,p<<1);
update(tl,tr,val,mid+1,r,p<<1|1);
pushup(p);
}
int query(ll val,int l,int r,int p){
if(l==r){
return l;
}
pushdown(p,l,r);
int mid=l+r>>1;
if(val<tree[p<<1].mex)
return query(val,l,mid,p<<1);
else return query(val,mid+1,r,p<<1|1);
}
int head[maxn],nex[maxn];
bool vis[maxn];
int main(){
int n;
while(scanf("%d",&n)&&n){
memset(head,0x3f,sizeof head);
memset(vis,0,sizeof vis);
int k=0;
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]>n) a[i]=n+1;
vis[a[i]]=1;
for(int j=k;j<=n;j++){
if(!vis[j]){
tmp[i]=j;
k=j;
break;
}
}
}
for(int i=n;i>0;i--){
nex[i]=head[a[i]];
head[a[i]]=i;
}
build(1,1,n);
ll ans=0;
ans+=tree[1].sum;
for(int i=1;i<=n;i++){
update(i,i,0ll,1,n,1);
if(tree[1].mex>a[i]){
int pos=query(a[i],1,n,1);
if(pos<nex[i]){
update(pos,nex[i]-1,a[i],1,n,1);
}
}
ans+=tree[1].sum;
}
printf("%lld\n",ans);
}
return 0;
}