bzoj 3339 Rmq Problem / mex

题目

我的树状数组怎么那么慢啊

就是一道水题,我们考虑一下对于一个区间\([l,r]\)什么样的数能被计算

显然需要对于一个\(j\),需要满足\(j<l\)\(nxt_{j}>r\),或者\(j>r\)\(lst_j<l\),这样的\(a_j\)才能被计算到

发现这不就是一个数点吗,于是我们扫描线加灵活的树状数组就做完了

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define lb(i) ((i)&(-i))
#define getchar() (S==T&&(T=(S=BB)+fread(BB,1,1<<15,stdin),S==T)?EOF:*S++)
char BB[1<<18],*S = BB,*T=BB; 
const int maxn=200005;
const int inf=999999999;
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct Ask{int l,r,rk;}q[maxn];
int n,m,ans,sz;
inline int min(int a,int b) {return a<b?a:b;}
int a[maxn],lst[maxn],nxt[maxn],Ans[maxn],ma[maxn],pos[maxn],c[maxn],d[maxn];
inline int cmp(Ask A,Ask B) {return A.l<B.l;}
inline int cop(Ask A,Ask B) {return A.r>B.r;}
inline void change(int x,int val) {for(re int i=x;i;i-=lb(i)) d[i]=min(d[i],val);}
inline void add(int x,int val) {for(re int i=x;i<=n+1;i+=lb(i)) d[i]=min(d[i],val);}
inline int ask(int x) {int now=inf,i;for(i=x;i;i-=lb(i)) now=min(now,d[i]);return now;}
inline int query(int x) {int now=inf,i;x++;for(i=x;i<=n+1;i+=lb(i)) now=min(now,d[i]);return now;}
inline void work() {
	ans=inf;
	if(c[1]!=0) {ans=0;return;}
	for(re int i=2;i<=sz;i++) {
		if(c[i]!=c[i-1]+1) {ans=c[i-1]+1;return;} 
	} 
	ans=c[sz]+1;
}
inline int find(int x) {
	int l=1,r=sz;
	while(l<=r) {
		int mid=l+r>>1;if(c[mid]==x) return mid;
		if(c[mid]<x) l=mid+1;else r=mid-1;
	}
	return 0;
}
int main() {
	n=read(),m=read();
	for(re int i=1;i<=n;i++) c[i]=a[i]=read();
	std::sort(c+1,c+n+1);sz=std::unique(c+1,c+n+1)-c-1;
	for(re int i=n;i;--i) {
		pos[i]=find(a[i]);
		nxt[i]=ma[pos[i]],ma[pos[i]]=i;
	}
	memset(ma,0,sizeof(ma));
	for(re int i=1;i<=n;i++) lst[i]=ma[pos[i]],ma[pos[i]]=i;
	for(re int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].rk=i;
	for(re int i=1;i<=n;i++) if(!nxt[i]) nxt[i]=n+1;
	std::sort(q+1,q+m+1,cmp);
	for(re int i=1;i<=n+1;i++) d[i]=inf;
	for(re int i=1;i<=m;i++) Ans[i]=inf;
	int now=1;
	for(re int i=1;i<=m;i++) {
		while(now<q[i].l) {change(nxt[now],a[now]);now++;}
		Ans[q[i].rk]=min(Ans[q[i].rk],query(q[i].r));
	}
	for(re int i=1;i<=n;i++) d[i]=inf;
	std::sort(q+1,q+m+1,cop);
	now=n;
	for(re int i=1;i<=m;i++) {
		while(now>q[i].r) {add(lst[now]+1,a[now]);now--;}
		Ans[q[i].rk]=min(Ans[q[i].rk],ask(q[i].l));
	}
	work();
	for(re int i=1;i<=m;i++) printf("%d\n",min(Ans[i],ans));
	return 0;
}
posted @ 2019-03-16 17:03  asuldb  阅读(121)  评论(0编辑  收藏  举报