hdu 4747 Mex
来源:互联网 发布:汉文化复兴 知乎 编辑:程序博客网 时间:2024/06/10 22:15
题意:求所有子区间Mex的和。Mex是最小的,不存在集合里的非负整数
思路:
首先考虑从1开始的所以Mex值,必然是非递减的,并且可以O(n)求出。(具体看代码)
先考虑如何从1开始的Mex值求出从2开始的Mex值
1.如果Mex<a[1],那么去掉后Mex值不变
2.如果Mex>a[1],并且该区间内不包含另外一个a[x]==a[1],那么Mex=a[1]。
那么我们需要先预处理出next数组,保存下一个a[i]的位置,那么每次把这样一段区间内的大于a[i]的值置为a[i]即可,由于Mex单调,那么我们只要找到位置最靠前的并且大于a[i]的,然后把改位置以后,下一个a[i]的位置之前的值全部置为a[i]即可。
那么我们可以用线段树来维护修改,查询的操作。
#include <iostream>#include <cstdio>#include <cstring>#define ls (t<<1)#define rs (t<<1|1)#define midt (tr[t].l+tr[t].r>>1)using namespace std;const int maxn=2e5+9;int a[maxn],now[maxn],next[maxn],first[maxn];bool flag[maxn];int n;struct{ int l,r,max; long long sum,lazy;}tr[maxn<<2];void pushup(int t){ tr[t].sum=tr[ls].sum+tr[rs].sum; tr[t].max=max(tr[ls].max,tr[rs].max);}void maketree(int t,int l,int r){ tr[t].l=l; tr[t].r=r; tr[t].lazy=-1; if(l==r) { tr[t].sum=now[l]; tr[t].max=now[l]; return ; } maketree(ls,l,midt); maketree(rs,midt+1,r); pushup(t);}void pushdown(int t){ if(tr[t].lazy==-1) return; tr[ls].sum=(tr[ls].r-tr[ls].l+1)*tr[t].lazy; tr[rs].sum=(tr[rs].r-tr[rs].l+1)*tr[t].lazy; tr[ls].max=tr[rs].max=tr[t].lazy; tr[ls].lazy=tr[rs].lazy=tr[t].lazy; tr[t].lazy=-1;}int query(int t,int tmp){ if(tr[t].max<tmp) return n+1; if(tr[t].l==tr[t].r) return tr[t].l; pushdown(t); if(tr[ls].max>=tmp) return query(ls,tmp); return query(rs,tmp);}void modify(int t,int l,int r,long long tmp){ if(tr[t].l==l&&tr[t].r==r) { tr[t].sum=tmp*(r-l+1); tr[t].lazy=tr[t].max=tmp; return ; } pushdown(t); if(r<=midt) modify(ls,l,r,tmp); else if(midt+1<=l) modify(rs,l,r,tmp); else { modify(ls,l,midt,tmp); modify(rs,midt+1,r,tmp); } pushup(t);}int main(){// freopen("in.txt","r",stdin); while(scanf("%d",&n),n) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); memset(flag,0,sizeof(flag)); for(int i=1,top=0;i<=n;i++) { if(a[i]<=n) flag[a[i]]=1; while(flag[top]) top++; now[i]=top; } for(int i=n;i>=0;i--) first[i]=n+1; for(int i=n;i>=1;i--) if(a[i]<=n) { next[i]=first[a[i]]; first[a[i]]=i; } else next[i]=n+1; maketree(1,1,n); long long ans=tr[1].sum; for(int i=1;i<n;i++) { int ll=query(1,a[i]); if(ll<=next[i]-1) modify(1,ll,next[i]-1,a[i]); ans+=tr[1].sum; } cout<<ans<<endl; } return 0;}
- hdu 4747 Mex
- HDU 4747 Mex
- hdu-4747-Mex
- hdu 4747 Mex
- hdu 4747 Mex
- hdu 4747 Mex
- HDU 4747 Mex
- HDU 4747 Mex
- hdu 4747 Mex
- HDU 4747 Mex
- HDU-4747 Mex
- [HDU 4747 Mex] Mex函数 线段树
- hdu 4747 Mex (线段树)
- hdu 4747 Mex 线段树
- HDU 4747 Mex (线段树)
- HDU 4747 Mex 区间更新
- hdu 4747Mex【线段树】
- HDU 4747 Mex (线段树)
- 编程之路,给自己一个方法,一个提醒
- Installing GRUB on a Hard Disk Image File
- Exchange 2010灾备站点激活!
- hdu 2197 本原串 找规律+快速幂+映射
- UVA 11584 Partitioning by Palindromes 动态规划 入门
- hdu 4747 Mex
- android中加载图片时出现oom
- va_start和va_end使用详解
- 开启IOS7新时代
- hdu_2063 过山车 匈牙利算法的bfs写法
- 将4字节数据二进制模式中001替换为011
- 解决EMF DanglingHREFException的问题
- 自定义basic_streambuf
- 如何集成CKFinder(1)