【题意概述】

  一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和。

【题解】

  扫描线+线段树。

  我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到右Mex单调上升。

  然后我们把区间左端点逐渐向右边移动,也就是扫描线是左端点。

  我们可以发现每次移动的影响就是 [这个数的位置, 这个数下一次出现的位置) 这个区间内大于这个数的Mex全部变为这个数。

  那么我们在线段树上二分出第一个大于等于Mex的位置,然后区间修改即可。

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define rg register
#define N 200010
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((a[u].l+a[u].r)>>1)
using namespace std;
int n,m,v[N],b[N],c[N],nxt[N],pos[N],mex[N];
LL ans,u[N];
struct tree{int l,r,nl,nr; LL sum; bool tag;}a[N<<];
inline int read(){
int k=,f=; char c=getchar();
while(c<''||c>'')c=='-'&&(f=-),c=getchar();
while(''<=c&&c<='')k=k*+c-'',c=getchar();
return k*f;
}
void build(int u,int l,int r){
a[u].l=l; a[u].r=r; a[u].tag=;
if(l<r){
build(ls,l,mid); build(rs,mid+,r);
a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr;
}
else a[u].sum=a[u].nl=a[u].nr=mex[l];
}
inline void pushdown(int u){
a[ls].tag=a[rs].tag=;
a[ls].nl=a[ls].nr=a[rs].nl=a[rs].nr=a[u].nl;
a[ls].sum=(a[ls].r-a[ls].l+)*a[ls].nl;
a[rs].sum=(a[rs].r-a[rs].l+)*a[rs].nl;
a[u].tag=;
}
void update(int u,int l,int r,int num){
if(l<=a[u].l&&a[u].r<=r&&a[u].nl>num){
a[u].tag=; a[u].nl=a[u].nr=num; a[u].sum=(a[u].r-a[u].l+)*num;
return;
}
if(a[u].nr<=num) return;
if(a[u].tag) pushdown(u);
if(a[ls].nr>num&&l<=mid) update(ls,l,r,num);
if(r>mid) update(rs,l,r,num);
a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr;
}
LL query(int u,int l,int r){
if(l<=a[u].l&&a[u].r<=r) return a[u].sum;
if(a[u].tag) pushdown(u); LL ret=;
if(l<=mid) ret+=query(ls,l,r);
if(r>mid) ret+=query(rs,l,r);
return ret;
}
inline void Pre(){
ans=;
memset(pos,,sizeof(pos));
memset(u,,sizeof(u));
}
int main(){
while(){
n=read(); if(!n) break;
Pre();
for(rg int i=;i<=n;i++) v[i]=b[i]=read();
sort(b+,b++n); m=unique(b+,b++n)-b-;
for(rg int i=;i<=n;i++) c[i]=lower_bound(b+,b++m,v[i])-b;
// for(rg int i=1;i<=n;i++) printf("%d ",c[i]); puts("c");
for(rg int i=n;i;i--) nxt[i]=(pos[c[i]])?pos[c[i]]:n+,pos[c[i]]=i;
// for(rg int i=1;i<=n;i++) printf("%d ",nxt[i]); puts("");
int now=;
for(rg int i=;i<=n;i++){
if(v[i]<=n) u[v[i]]=;
while(u[now]) now++;
ans+=(mex[i]=now);
}
// for(rg int i=1;i<=n;i++) printf("%d ",mex[i]);
// printf("ans=%lld\n",ans);
build(,,n);
for(rg int i=;i<=n;i++){
update(,i+,nxt[i]-,v[i]);
ans+=query(,i+,n);
// printf("ans=%lld\n",ans);
}
printf("%lld\n",ans);
}
return ;
}

最新文章

  1. ubuntu开启SSH服务
  2. 论文阅读(Xiang Bai——【arXiv2016】Scene Text Detection via Holistic, Multi-Channel Prediction)
  3. 【安全测试】 WebScarab安装方法
  4. oc语言常用的字符串函数
  5. 怎么在OCR文字识别软件中安装和启动 OCR文字识别软件 Hot Folder
  6. android 二维码生成+扫描
  7. DropDownList的多级联动
  8. 2140: 稳定婚姻 - BZOJ
  9. JSP学习笔记(一)
  10. ThinkPHP函数详解:cache方法
  11. 找回linux丢失的磁盘空间
  12. java properties 对list的支持
  13. Vue实现商城里面多个商品计算,全选,删除
  14. JavaScript一看就懂(1)作用域
  15. 如何从0开发一个Atom组件
  16. Struts2--标签tag
  17. 树莓派播放视频的播放器omxplayer
  18. mac pfctl / centos iptables 使用
  19. java实操之使用jcraft进行sftp上传下载文件
  20. UI框架搭建DAY1

热门文章

  1. input type=&quot;file&quot;文件上传到后台读取
  2. 【爬坑系列】之解读kubernetes的认证原理&amp;实践
  3. 洛谷P4141消失之物(背包经典题)——Chemist
  4. Spark SQL概念学习系列之Spark SQL入门
  5. MFC中利用CString和Format成员函数将数字格式化输出
  6. BZOJ2553 [BJWC2011]禁忌
  7. Data Center Maintenance CodeForces - 950E
  8. 二分查找+数学 HDOJ 4342 History repeat itself
  9. 找规律/贪心 Codeforces Round #310 (Div. 2) A. Case of the Zeros and Ones
  10. IOS利用Core Text对文字进行排版 - 转