BZOJ3489 A simple rmq problem

设第i个数上一次出现的位置为lst[i],下一次出现的位置为nxt[i],那么第i个数可以用作更新答案的条件就是lst[i]r&&l<=i<=r

把lst,nxt和i分别看作三维坐标,问题就转化为了立方体求最大值

对于二维情况,我们可以用二维线段树搞,现在是三维,但是我们发现lst这一维在查询的时候左端点一直为0(我觉得用接地这个词语来形容特别形象-_-),所以我们可以通过可持久化来维护第一维,由于外层进行了可持久化,需要有将内层元素更新并保留原版本的操作,所以内层也要跟着可持久化

具体点说就是用主席树套主席树,每个版本都是一个二维线段树,第i个版本代表lst<=i的二维线段树的总和(前缀和),然后在修改的时候由于之前版本的二维线段树需要保留原来版本的信息,所以内层线段树也要用主席树

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define MAXN 100010
#define MAXM 40000010
#define INF 1000000000
#define MOD 1000000007
#define ll long long
#define eps 1e-8
char xB[1<<15],*xS=xB,*xT=xB;
#define getc() (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++)
inline int read()
{
int x=0,f=1;char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
struct pt{
	int x;
	int y;
	int z;
	int v;
	pt(){
		
	}
	pt(int _x,int _y,int _z,int _v){
		x=_x;
		y=_y;
		z=_z;
		v=_v;
	}
	friend bool operator <(pt x,pt y){
		return x.x>1;
	if(iv.z<=mid){
		change(son[x][0],son[xx][0],y,mid,iv);
	}else{
		change(son[x][1],son[xx][1],mid+1,z,iv);
	}
}
void tochange(int &x,int xx,int y,int z,pt iv){
	x=++tot;
	memcpy(son[x],son[xx],sizeof(son[x]));
	change(v[x],v[xx],1,n+2,iv);
	if(y==z){
		return ;
	}
	int mid=y+z>>1;
	if(iv.y<=mid){
		tochange(son[x][0],son[xx][0],y,mid,iv);
	}else{
		tochange(son[x][1],son[xx][1],mid+1,z,iv);
	}
}
int ask(int x,int y,int z,int l,int r){
	if(!x){
		return 0;
	}
	if(y==l&&z==r){
		return v[x];
	}
	int mid=y+z>>1;
	if(r<=mid){
		return ask(son[x][0],y,mid,l,r);
	}else if(l>mid){
		return ask(son[x][1],mid+1,z,l,r);
	}else{
		return max(ask(son[x][0],y,mid,l,mid),ask(son[x][1],mid+1,z,mid+1,r));
	}
}
int toask(int x,int y,int z,int l,int r,int L,int R){
	if(!x){
		return 0;
	}
	if(y==l&&z==r){
		return ask(v[x],1,n+2,L,R);
	}
	int mid=y+z>>1;
	if(r<=mid){
		return toask(son[x][0],y,mid,l,r,L,R);
	}else if(l>mid){
		return toask(son[x][1],mid+1,z,l,r,L,R);
	}else{
		return max(toask(son[x][0],y,mid,l,mid,L,R),toask(son[x][1],mid+1,z,mid+1,r,L,R));
	}
}
int main(){
	int i,x,y,X,Y;
	n=read();
	m=read();
	for(i=1;i<=n;i++){
		tai[i]=1;
	}
	for(i=2;i<=n+1;i++){
		a[i]=read();
		nxt[tai[a[i]]]=i;
		lst[i]=tai[a[i]];
		tai[a[i]]=i;
	}
	for(i=1;i<=n;i++){
		nxt[tai[i]]=n+2;
	}
	for(i=2;i<=n+1;i++){
		p[i-1]=pt(lst[i],nxt[i],i,a[i]);
	}
	sort(p+1,p+n+1);
	int wzh=1;
	for(i=1;i<=n+2;i++){
		rt[i]=rt[i-1];
		while(p[wzh].x==i&&wzh<=n){
			tochange(rt[i],rt[i],1,n+2,p[wzh]);
			wzh++;
		}
	}
	while(m--){
		X=read();
		Y=read();
		X=(X+la)%n+1;
		Y=(Y+la)%n+1;
		x=min(X,Y);
		y=max(X,Y);
		x++;
		y++;
		printf("%d\n",la=toask(rt[x-1],1,n+2,y+1,n+2,x,y));
	}
	return 0;
}

/*
10 10
6 4 9 10 9 10 9 4 10 4 
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9



*/


你可能感兴趣的:(BZOJ,主席树,树套树,二维线段树)