BZOJ3489 A simple rmq problem

Description

因爲是OJ上的題,就簡單點好了。給出一個長度爲n的序列,給出M個詢問:在[l,r]之間找到一個在這個區間裏只出現過一次的數,並且要求找的這個數儘可能大。如果找不到這樣的數,則直接輸出0。我會採取一些措施強制在線。


Input

第一行爲兩個整數N,M。M是詢問數,N是序列的長度(N<=100000,M<=200000)

第二行爲N個整數,描述這個序列{aia_i},其中所有1<=aia_i<=N

再下面M行,每行兩個整數x,y,

詢問區間[l,r]由下列規則產生(OIER都知道是怎樣的吧>_<):

l=min((x+lastans)mod n+1,(y+lastans)mod n+1);

r=max((x+lastans)mod n+1,(y+lastans)mod n+1);

Lastans表示上一個詢問的答案,一開始lastans爲0


Output

一共M行,每行給出每個詢問的答案。


Solution

KD-tree做法:

想法神仙,實現簡單。

設pre[i]爲上一個值爲aia_i的位置
設nxt[i]爲下一個值爲aia_i的位置

n個三維點,座標爲(pre[i],i,nxt[i]),權值爲aia_i
插入到kd-tree中,直接暴力查,普通的判一下區間就行了。

要打一下ans的剪枝和左右兒子的判斷剪枝。


Code

#include<bits/stdc++.h>
using namespace std;
const double alpha=0.7;
struct pt{
	int d[3],w;
	void make(int x,int y,int z,int v){
		d[0]=x,d[1]=y,d[2]=z,w=v;
	}
}a[200010];
struct data{
	int mx[3],mn[3],maxn,ls,rs,sz;
	pt p;
}tree[200010];
int b[200010];
int c[200010];
int pre[200010];
int nxt[200010];
int stk[200010];
int nt[3]={1,2,0};
int n,m,ans,tot,word,top,rt,lans;
int operator <(pt u,pt v){
	return u.d[word]<v.d[word];
}
int newnode(){
	if(top) return stk[top--];
	return ++tot;
}
void up(int x){
	int l=tree[x].ls;
	int r=tree[x].rs;
	for(int i=0;i<3;i++){
		tree[x].mx[i]=tree[x].mn[i]=tree[x].p.d[i];
		if(l) tree[x].mx[i]=max(tree[x].mx[i],tree[l].mx[i]);
		if(r) tree[x].mx[i]=max(tree[x].mx[i],tree[r].mx[i]);
		if(l) tree[x].mn[i]=min(tree[x].mn[i],tree[l].mn[i]);
		if(r) tree[x].mn[i]=min(tree[x].mn[i],tree[r].mn[i]);
	}
	tree[x].maxn=max(max(tree[l].maxn,tree[r].maxn),tree[x].p.w);
	tree[x].sz=tree[l].sz+tree[r].sz+1;
}
int build(int l,int r,int wd){
	if(l>r) return 0;
	int mid=(l+r)>>1;
	int x=newnode();
	word=wd,nth_element(a+l,a+mid,a+r+1);
	tree[x].p=a[mid];
	tree[x].ls=build(l,mid-1,nt[wd]);
	tree[x].rs=build(mid+1,r,nt[wd]);
	up(x); return x;
}
bool in(int xl,int xr,int l,int r,int ql,int qr){
	return (ql<=xl&&qr>=xr&&ql>=l&&qr<=r);
}
bool out(int xl,int xr,int l,int r,int ql,int qr){
	return (ql>xr||qr<xl||ql<l||qr>r);
}
void query(int x,int ql,int qr){
	if(x==0) return;
	if(tree[x].maxn<=lans) return;
	int ans=0,l=tree[x].ls,r=tree[x].rs;
	if(in(tree[x].mn[0],tree[x].mx[0],tree[x].mx[1],tree[x].mn[2],ql,qr)) lans=max(lans,tree[x].maxn); 
	if(out(tree[x].mn[0],tree[x].mx[0],tree[x].mn[1],tree[x].mx[2],ql,qr)) return; 
	if(in(tree[x].p.d[0],tree[x].p.d[0],tree[x].p.d[1],tree[x].p.d[2],ql,qr)) lans=max(tree[x].p.w,lans); 
	if(tree[l].maxn>tree[r].maxn){
		query(l,ql,qr);
		query(r,ql,qr);
	}
	else{
		query(r,ql,qr);
		query(l,ql,qr);
	}
}
int main(){
	int x,y,l,r;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&b[i]);
	for(int i=1;i<=n;i++){
		pre[i]=c[b[i]]+1;
		c[b[i]]=i;
	}
	for(int i=1;i<=n;i++) c[i]=n+1;
	for(int i=n;i;i--){
		nxt[i]=c[b[i]]-1;
		c[b[i]]=i;
	}
	for(int i=1;i<=n;i++)
	a[i].make(i,pre[i],nxt[i],b[i]);
	rt=build(1,n,0);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		l=min((x+lans)%n+1,(y+lans)%n+1);
		r=max((x+lans)%n+1,(y+lans)%n+1);
		lans=0,query(rt,l,r);
		printf("%d\n",lans);
	}
}
發佈了27 篇原創文章 · 獲贊 5 · 訪問量 2756
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章