E.Complicated Computations
如果一个区间的mex=amex=amex=a,满足以下条件:
- 区间未出现aaa
- 区间出现1→a−11\to a-11→a−1
因此若考虑是否存在一个区间的mex值是aaa,我们尝试把整个区间以aaa为端点划分成若干段,只要每一段内(不含端点a)中出现1→a−11\to a-11→a−1那么就存在一个区间的mex值是aaa
a…a…a…a…a…a…aa\dots a\dots a\dots a\dots a\dots a\dots aa…a…a…a…a…a…a
即只要有一个…\dots…存在1→a−11\to a-11→a−1那么就存在区间mex=amex=amex=a
那么如何确定…\dots…存在1→a−11\to a-11→a−1?
不妨假设两个a的位置一个是LLL,一个是RRR,那么我们现在判定[L+1,R−1][L+1,R-1][L+1,R−1]的区间是否存在1→a−11\to a-11→a−1。那么不难发现1→a−11\to a-11→a−1最后一次出现的位置>L>L>L
由此用权值线段树维护每一个数最后一次出现的位置,并且记录上一次某数出现的位置查询即可。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=100010;
int a[N],n;
bool st[N];
int last[N];
int pos[N<<2];
void modify(int u,int l,int r,int k,int x)
{if(l==r) {pos[u]=x;return;}int mid=l+r>>1;if(k<=mid) modify(u<<1,l,mid,k,x);else modify(u<<1|1,mid+1,r,k,x);pos[u]=min(pos[u<<1],pos[u<<1|1]);
}
int query(int u,int l,int r,int L,int R)
{if(l>=L&&r<=R) return pos[u];int mid=l+r>>1;if(R<=mid)return query(u<<1,l,mid,L,R);else if(L>mid)return query(u<<1|1,mid+1,r,L,R);else return min(query(u<<1,l,mid,L,R),query(u<<1|1,mid+1,r,L,R));
}
int main()
{IO;int T=1;//cin>>T;for(int ca=1;ca<=T;ca++){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++){if(a[i]!=1) st[1]=1;if(a[i]>1&&query(1,1,n,1,a[i]-1)>last[a[i]]) st[a[i]]=1;last[a[i]]=i;modify(1,1,n,a[i],i);}for(int i=2;i<=n+1;i++) //枚举到n+1有可能有区间的mex=n+1if(query(1,1,n,1,i-1)>last[i]) st[i]=1;int res=1;while(st[res]) res++;cout<<res<<'\n';}return 0;
}
这题竟然还卡时间?用build版本的线段树就TLE,只能查询时传递区间。。。
本题还可以效仿下面题目的做法,用线段树维护mex,每次区间修改aia_iai 时便可能存在区间的mex是 aia_iai
#include<bits/stdc++.h>using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
int a[N],n;
int mex[N],ne[N],pos[N];
bool st[N];
struct node
{int l,r;ll tag;ll mn,mx;
}t[N<<2];
void pushup(int u)
{t[u].mn=min(t[u<<1].mn,t[u<<1|1].mn);t[u].mx=max(t[u<<1].mx,t[u<<1|1].mx);
}
void build(int u,int l,int r)
{t[u]={l,r,-1,0x3f3f3f3f,-0x3f3f3f3f};if(l==r){t[u].mn=t[u].mx=mex[l]; return;}int mid=l+r>>1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);pushup(u);
}
void pushdown(int u)
{if(t[u].tag==-1) return;t[u<<1].tag=t[u].tag;t[u<<1|1].tag=t[u].tag;t[u<<1].mn=t[u].tag;t[u<<1|1].mn=t[u].tag;t[u<<1].mx=t[u].tag;t[u<<1|1].mx=t[u].tag;t[u].tag=-1;
}
bool modify(int u,int l,int r,int x)
{if(l>r) return 0;if(t[u].mx<=x) return 0;if(t[u].l>=l&&t[u].r<=r&&t[u].mn>x){t[u].tag=x;t[u].mn=x;t[u].mx=x;return 1;}pushdown(u);int mid=t[u].l+t[u].r>>1;bool ok=0;if(l<=mid) ok|=modify(u<<1,l,r,x);if(r>mid) ok|=modify(u<<1|1,l,r,x);pushup(u);return ok;
}int vis[N];int main()
{scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);int now=1;for(int i=1;i<=n;i++){st[a[i]]=1;while(st[now]) now++;mex[i]=now;vis[now]=1;}//for(int i=1;i<=n;i++) cout<<mex[i]<<' ';cout<<'\n';for(int i=0;i<=n+1;i++) pos[i]=n+1;for(int i=n;i;i--){ne[i]=pos[a[i]];pos[a[i]]=i;}build(1,1,n);for(int i=1;i<=n;i++){int l=i+1,r=ne[i]-1;if(modify(1,l,r,a[i])) vis[a[i]]=1;}//for(int i=1;i<=n;i++) cout<<vis[i]<<' ';cout<<'\n';int res=1; while(vis[res]) res++;printf("%d\n",res);return 0;
}
Hdu. Mex
大佬题解
mex(1,i)mex(1,i)mex(1,i)具有单调递增的性质。
#include<bits/stdc++.h>#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
int a[N],n;
int mex[N],ne[N],pos[N];
bool st[N];
struct node
{int l,r;ll s;ll lazy;
}tree[N<<2];
void pushup(int u)
{tree[u].s=tree[u<<1].s+tree[u<<1|1].s;
}
void build(int u,int l,int r)
{tree[u]={l,r,0,-1};if(l==r){tree[u].s=mex[l]; return;}int mid=l+r>>1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);pushup(u);
}
void pushdown(int u)
{if(tree[u].lazy==-1) return;int lenl=tree[u<<1].r-tree[u<<1].l+1;int lenr=tree[u<<1|1].r-tree[u<<1|1].l+1;tree[u<<1].s=1ll*lenl*tree[u].lazy;tree[u<<1|1].s=1ll*lenr*tree[u].lazy;tree[u<<1].lazy=tree[u].lazy;tree[u<<1|1].lazy=tree[u].lazy;tree[u].lazy=-1;
}
void modify(int u,int l,int r,int x)
{if(tree[u].l>=l&&tree[u].r<=r){tree[u].s=1ll*x*(tree[u].r-tree[u].l+1);tree[u].lazy=x;return;}pushdown(u);int mid=tree[u].l+tree[u].r>>1;if(l<=mid) modify(u<<1,l,r,x);if(r>mid) modify(u<<1|1,l,r,x);pushup(u);
}
ll query(int u,int l,int r)
{if(tree[u].l>=l&&tree[u].r<=r) return tree[u].s;pushdown(u);int mid=tree[u].l+tree[u].r>>1;ll v=0;if(l<=mid) v+=query(u<<1,l,r);if(r>mid) v+=query(u<<1|1,l,r);return v;
}
int main()
{while(scanf("%d",&n),n){for(int i=1;i<=n;i++){scanf("%d",&a[i]);if(a[i]>n) a[i]=n+1;}for(int i=0;i<=n+1;i++) st[i]=0;int now=0;for(int i=1;i<=n;i++){st[a[i]]=1;while(st[now]) now++;mex[i]=now;}for(int i=0;i<=n+1;i++) pos[i]=n+1;for(int i=n;i;i--){ne[i]=pos[a[i]];pos[a[i]]=i;}build(1,1,n);ll res=0;for(int i=1;i<=n;i++){res+=query(1,i,n);int l=i,r=ne[i]-1;while(l<r){int mid=l+r>>1;if(query(1,mid,mid)>a[i]) r=mid;else l=mid+1;}if(query(1,l,l)>a[i]) modify(1,l,ne[i]-1,a[i]);}printf("%lld\n",res);}return 0;
}
同时维护最大最小值,势能去掉二分
#include<bits/stdc++.h>using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int N=200010;
int a[N],n;
int mex[N],ne[N],pos[N];
bool st[N];
struct node
{int l,r;ll s;ll tag;ll mn,mx;
}t[N<<2];
void pushup(int u)
{t[u].s=t[u<<1].s+t[u<<1|1].s;t[u].mn=min(t[u<<1].mn,t[u<<1|1].mn);t[u].mx=max(t[u<<1].mx,t[u<<1|1].mx);
}
void build(int u,int l,int r)
{t[u]={l,r,0,-1,0x3f3f3f3f,-0x3f3f3f3f};if(l==r){t[u].s=t[u].mn=t[u].mx=mex[l]; return;}int mid=l+r>>1;build(u<<1,l,mid);build(u<<1|1,mid+1,r);pushup(u);
}
void pushdown(int u)
{if(t[u].tag==-1) return;int lenl=t[u<<1].r-t[u<<1].l+1;int lenr=t[u<<1|1].r-t[u<<1|1].l+1;t[u<<1].s=1ll*lenl*t[u].tag;t[u<<1|1].s=1ll*lenr*t[u].tag;t[u<<1].tag=t[u].tag;t[u<<1|1].tag=t[u].tag;t[u<<1].mn=t[u].tag;t[u<<1|1].mn=t[u].tag;t[u<<1].mx=t[u].tag;t[u<<1|1].mx=t[u].tag;t[u].tag=-1;
}
void modify(int u,int l,int r,int x)
{if(t[u].mx<=x) return;if(t[u].l>=l&&t[u].r<=r&&t[u].mn>x){t[u].s=1ll*x*(t[u].r-t[u].l+1);t[u].tag=x;t[u].mn=x;t[u].mx=x;return;}pushdown(u);int mid=t[u].l+t[u].r>>1;if(l<=mid) modify(u<<1,l,r,x);if(r>mid) modify(u<<1|1,l,r,x);pushup(u);
}
ll query(int u,int l,int r)
{if(t[u].l>=l&&t[u].r<=r) return t[u].s;pushdown(u);int mid=t[u].l+t[u].r>>1;ll v=0;if(l<=mid) v+=query(u<<1,l,r);if(r>mid) v+=query(u<<1|1,l,r);return v;
}
int main()
{while(scanf("%d",&n),n){for(int i=1;i<=n;i++){scanf("%d",&a[i]);if(a[i]>n) a[i]=n+1;}for(int i=0;i<=n+1;i++) st[i]=0;int now=0;for(int i=1;i<=n;i++){st[a[i]]=1;while(st[now]) now++;mex[i]=now;}for(int i=0;i<=n+1;i++) pos[i]=n+1;for(int i=n;i;i--){ne[i]=pos[a[i]];pos[a[i]]=i;}build(1,1,n);ll res=0;for(int i=1;i<=n;i++){res+=query(1,i,n);int l=i,r=ne[i]-1;if(l<=r) modify(1,l,r,a[i]);}printf("%lld\n",res);}return 0;
}
两者时间复杂度对比,效果还挺明显。