手算可以发现,当一组数列a[x],去掉a[0]后,那么之后新的数列数列的mex值将会发生变化
对于第二组样例 1 0 2 0 1
我们一步步算
得到mex(i,j)(j>=i)
0+2+3+3+3 = 11 //第一次可以得到mex(1,i)(1<=i<=n)
1+1+1+3 = 6
0+1+3 = 4
1+2 = 3
0 = 0 sum=24
每次删除a[i]时,mex的值只影响到nextpos[a[i]],nextpos表示a[i]下一次出现的值的下标,也就是对于区间[i+1,nextpos[a[i]]中的大于a[i]数字改为a[i]。区间更新可以用线段树来维护。这样就将二维的矩阵mex化为一维处理了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
#define maxn 200005
#define LL long long
int a[maxn];
int num[maxn];
int p[maxn];
bool vis[maxn];
vector<int>pos[maxn];
vector<int>::iterator it;
set<int>lst;
set<int>::iterator it1;
struct node
{
int v,i;
bool operator < (const node& tmp) const
{
return v<tmp.v;
}
} b[maxn];
int n;
struct SegTree
{
int l,r;
int mi,ma;
LL sum;
int flag;
int len()
{
return r-l+1;
}
} tree[maxn<<2];
inline void pushup(int rt)
{
int ls=rt<<1,rs=ls+1;
tree[rt].sum=tree[ls].sum+tree[rs].sum;
tree[rt].mi=min(tree[ls].mi,tree[rs].mi);
tree[rt].ma=max(tree[ls].ma,tree[rs].ma);
}
inline void pushdown(int rt)
{
if(tree[rt].flag)
{
int ls=rt<<1,rs=rt<<1|1;
tree[ls].flag=tree[rs].flag=1;
tree[ls].mi=tree[rs].mi=tree[ls].ma=tree[rs].ma=tree[rt].mi;
tree[ls].sum=tree[ls].mi*tree[ls].len();
tree[rs].sum=tree[rs].mi*tree[rs].len();
tree[rt].flag=0;
}
}
void build(int rt,int l,int r)
{
tree[rt].l=l,tree[rt].r=r;
tree[rt].flag=0;
if(l==r)
{
tree[rt].mi=tree[rt].ma=tree[rt].sum=p[l];
return ;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int k)
{
if(r<l) return ;
if(tree[rt].l>=l&&tree[rt].r<=r&&tree[rt].mi>k)
{
tree[rt].mi=tree[rt].ma=k;
tree[rt].flag=1;
tree[rt].sum=k*tree[rt].len();
return ;
}
int mid=(tree[rt].l+tree[rt].r)>>1;
pushdown(rt);
int ls=rt<<1,rs=rt<<1|1;
if(l<=mid&&tree[ls].ma>k) update(ls,l,r,k);
if(r>mid&&tree[rs].ma>k) update(rs,l,r,k);
pushup(rt);
}
int main()
{
while(~scanf("%d",&n))
{
if(!n) break;
lst.clear();
memset(vis,0,sizeof(vis));
for(int i=0; i<=n; i++)
lst.insert(i);
for(int i=1; i<=n; i++)
{
scanf("%d",a+i);
b[i].v=a[i];
b[i].i=i;
}
sort(b+1,b+1+n);
int cnt=0;
for(int i=1; i<=n; i++)
{
if(i>1&&b[i].v==b[i-1].v) a[b[i].i]=cnt;
else a[b[i].i]=++cnt,num[cnt]=b[i].v;
}
for(int i=1; i<=cnt; i++) pos[i].clear();
for(int i=1; i<=n; i++) pos[a[i]].push_back(i);
for(int i=1; i<=cnt; i++) pos[i].push_back(n+1);
// for(int i=1; i<=cnt; i++)
// {
// printf("num'pos: %d\n",num[i]);
// for(it=pos[i].begin(); it!=pos[i].end(); it++)
// printf("%d ",*it);
// puts("");
// }
for(int i=1; i<=n; i++)
{
int t=num[a[i]];
if(t<=n&&!vis[t])
{
it1=lst.find(t);
lst.erase(it1);
vis[t]=1;
}
it1=lst.begin();
p[i]=*it1;
}
// for(int i=1; i<=n; i++) printf("%d ",p[i]);
// puts("");
build(1,1,n);
LL ans=tree[1].sum;
for(int i=1; i<n; i++)
{
pos[a[i]].erase(pos[a[i]].begin());
int nxt=*(pos[a[i]].begin());
update(1,1,i,0);
update(1,i+1,nxt-1,num[a[i]]);
ans+=tree[1].sum;
}
printf("%I64d\n",ans);
}
return 0;
}