HUAS 1483 mex(离线+线段树)
实在是太弱了。。。。
考虑离线,从mex[l,r]向mex[l,r+1]转移,显然是没啥东西可以记录的。。。
从mex[l,r]向mex[l+1,r]转移,记x=mex[l,r],如果[l+1,r]不出现a[l]的话,那么mex[l+1,r]=min(mex[l,r],a[l]).
有了这个性质的话,就可以考虑离线了。先预处理一遍to[]和mex[],to[i]表示i的后面下一个出现a[i]的数组下标,mex[i]表示mex[1,i]。
把询问按左端点升序排序,对于当前的左端点为1的排序,可以直接输出它的mex值。
当左端点向右移一位的时候,mex[2,j]=min(mex[1,j],a[1]).(j<to[1]).
如果暴力修改的话还是会超时的。
很幸运mex数组是单调非递减的。那么我们可以用线段树把区间[2,j]上的值取个min。用tag思想的话很容易做到logn。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vector> # include <queue> # include <stack> # include <map> # include <set> # include <cmath> # include <algorithm> using namespace std; # define lowbit(x) ((x)&(-x)) # define pi 3.1415926535 # define eps 1e-9 # define MOD 1000000007 # define INF 1000000000 # define mem(a,b) memset(a,b,sizeof(a)) # define FOR(i,a,n) for(int i=a; i<=n; ++i) # define FO(i,a,n) for(int i=a; i<n; ++i) # define bug puts("H"); # define lch p<<1,l,mid # define rch p<<1|1,mid+1,r # define mp make_pair # define pb push_back typedef pair<int,int> PII; typedef vector<int> VI; # pragma comment(linker, "/STACK:1024000000,1024000000") typedef long long LL; int Scan() { int res=0, flag=0; char ch; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+(ch-'0'); return flag?-res:res; } void Out(int a) { if(a<0) {putchar('-'); a=-a;} if(a>=10) Out(a/10); putchar(a%10+'0'); } const int N=200005; //Code begin... struct Node{int l, r, id;}node[N]; int seg[N<<2], a[N], mex[N], vis[N], to[N], now, tag[N<<2], ans[N], res; bool comp(Node a, Node b){return a.l<b.l;} void init(int p, int l, int r){ if (l<r) { int mid=(l+r)>>1; init(lch); init(rch); return ; } seg[p]=mex[l]; } void push_down(int p, int l, int r){ if (tag[p]==-1) return ; if (l==r) seg[p]=min(seg[p],tag[p]); else { tag[p<<1]=(tag[p<<1]==-1?tag[p]:min(tag[p],tag[p<<1])); tag[p<<1|1]=(tag[p<<1|1]==-1?tag[p]:min(tag[p],tag[p<<1|1])); } tag[p]=-1; } void update(int p, int l, int r, int L, int R, int val){ if (L>r||R<l) return ; push_down(p,l,r); if (L<=l&&R>=r) tag[p]=val; else { int mid=(l+r)>>1; update(lch,L,R,val); update(rch,L,R,val); } } void query(int p, int l, int r, int L){ if (L>r||L<l) return ; push_down(p,l,r); if (L==r&&L==l) res=seg[p]; else { int mid=(l+r)>>1; query(lch,L); query(rch,L); } } int main () { int n, q; mem(tag,-1); n=Scan(); q=Scan(); FOR(i,1,n) { a[i]=Scan(); if (vis[a[i]]) to[vis[a[i]]]=i; vis[a[i]]=i; while (vis[now]) ++now; mex[i]=now; } FOR(i,1,n) if (!to[i]) to[i]=n+1; FOR(i,1,q) node[i].l=Scan(), node[i].r=Scan(), node[i].id=i; sort(node+1,node+q+1,comp); now=1; init(1,1,n); FOR(i,1,q) { while (now!=node[i].l) { if (now+1<=to[now]-1) update(1,1,n,now+1,to[now]-1,a[now]); ++now; } query(1,1,n,node[i].r); ans[node[i].id]=res; } FOR(i,1,q) printf("%d\n",ans[i]); return 0; }