bzoj 3489: A simple rmq problem

Description

给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0, 强制在线。

Solution

\(pre[i]\) 表示 \(i\) 之前第一个与 \(a[i]\) 相同的位置
\(nxt[i]\) 表示 \(i\) 之后第一个与 \(a[i]\) 相同的位置
满足要求的位置是:
\(l<=i<=r,pre[i]<l,nxt[i]>r\)
可以看成是点 \((i,pre,nxt)\)
\(kdtree\) 维护一下包含所有点的区域就行了

#include<bits/stdc++.h>
using namespace std;
template<class T>void gi(T &x){
	int f;char c;
	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
}
const int N=1e5+10;
int n,Q,nxt[N],pre[N],la[N],a[N],D,rt,ans=0;
struct data{
	int a[3],mx[3],mn[3],w,l,r,v;
	inline int& operator [](int x){return a[x];}
}t[N];
inline bool operator <(data p,data q){return p[D]<q[D];}
inline void upd(int o){
	int l=t[o].l,r=t[o].r;
	for(int i=0;i<3;i++)t[o].mn[i]=t[o].mx[i]=t[o][i];
	for(int i=0;i<3;i++){
		if(l)t[o].mn[i]=min(t[o].mn[i],t[l].mn[i]),
				  t[o].mx[i]=max(t[o].mx[i],t[l].mx[i]);
		if(r)t[o].mn[i]=min(t[o].mn[i],t[r].mn[i]),
				  t[o].mx[i]=max(t[o].mx[i],t[r].mx[i]);
	}
   t[o].v=max(t[o].w,max(t[l].v,t[r].v));
}
inline int build(int l,int r){
	D=rand()%3;
	int mid=(l+r)>>1,o=mid;
	nth_element(t+l,t+mid,t+r+1);
	if(l<mid)t[o].l=build(l,mid-1);
	if(r>mid)t[o].r=build(mid+1,r);
	return upd(o),o;
}
int l,r;
inline bool check(int o){
	if(t[o].mn[0]>r || t[o].mx[0]<l)return 0;
	if(t[o].mn[1]>=l)return 0;
	if(t[o].mx[2]<=r)return 0;
	return 1;
}
inline void query(int o){
	if(!o || !check(o))return ;
	if(t[o].v<=ans)return ;
	if(t[o][0]>=l && t[o][0]<=r && t[o][1]<l && t[o][2]>r)ans=max(ans,t[o].w);
	query(t[o].l);query(t[o].r);
}
int main(){
	freopen("pp.in","r",stdin);
	freopen("pp.out","w",stdout);
	srand(19260817);
	cin>>n>>Q;
	for(int i=1;i<=n;i++)gi(a[i]),pre[i]=la[a[i]],la[a[i]]=i;
	memset(la,0,sizeof(la));
	for(int i=n;i>=1;i--)nxt[i]=la[a[i]]?la[a[i]]:n+1,la[a[i]]=i;
	for(int i=1;i<=n;i++)t[i][0]=i,t[i][1]=pre[i],t[i][2]=nxt[i],t[i].w=a[i];
	rt=build(1,n);
	int x,y;
	while(Q--){
		gi(x);gi(y);
		l=(x+ans)%n+1;r=(y+ans)%n+1;if(l>r)swap(l,r);
		ans=0;
		query(rt);
		printf("%d\n",ans);
	}
	return 0;
}

posted @ 2018-07-15 13:58  PIPIBoss  阅读(221)  评论(0编辑  收藏  举报