BZOJ 3489 A simple rmq problem(可持久化线段树)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3489

题意:一个数列。每次询问一个区间内出现一次的最大的数字是多少。

思路:设last[i]表示i位置的数字上一次出现的位置,next[i]类似。那么询问区间[L,R]时,这个区间的哪些数字可以只出现一次呢?是那些last值小于L且next值大于R的数字。因此按照last排序后,按照last可持久化。具体看代码吧 不好说

const int N=100005;



struct node

{

	int val,last,next,id;

};



node b[N];

int last[N],next[N],n,m;



struct Node1

{

	int Max;

	int L,R;

};



struct Node2

{

	int root;

	int L,R;

};





Node1 A[40000005];

Node2 a[N*20];

int ANum,aNum;



int cmp(node a,node b)

{

	return a.last<b.last;

}



int root[N];



void insert1(int &t,int L,int R,int pos,int val)

{

	int cur=++ANum;

	A[cur]=A[t];

	t=cur;

	A[t].Max=max(A[t].Max,val);



	if(L==R) return;



	int M=(L+R)>>1;

	if(pos<=M) insert1(A[t].L,L,M,pos,val);

	else insert1(A[t].R,M+1,R,pos,val);

}



void insert(int &t,int L,int R,int posX,int posY,int val)

{

	int cur=++aNum;

	a[cur]=a[t];

	t=cur;

	insert1(a[t].root,1,n,posY,val);

	if(L==R) return;

	int M=(L+R)>>1;

	if(posX<=M) insert(a[t].L,L,M,posX,posY,val);

	else insert(a[t].R,M+1,R,posX,posY,val);

}











int query1(int t,int L,int R,int ll,int rr)

{

	if(!t) return 0;

	if(L==ll&&R==rr) return A[t].Max;

	int M=(L+R)>>1;

	if(rr<=M) return query1(A[t].L,L,M,ll,rr);

	if(ll>M) return query1(A[t].R,M+1,R,ll,rr);

	int ans1=query1(A[t].L,L,M,ll,M);

	int ans2=query1(A[t].R,M+1,R,M+1,rr);

	return max(ans1,ans2);

}



int query(int t,int L,int R,int ll,int rr,int ll1,int rr1)

{

	if(L==ll&&R==rr) return query1(a[t].root,1,n,ll1,rr1);

	int M=(L+R)>>1;

	if(rr<=M) return query(a[t].L,L,M,ll,rr,ll1,rr1);

	if(ll>M) return query(a[t].R,M+1,R,ll,rr,ll1,rr1);

	int ans1=query(a[t].L,L,M,ll,M,ll1,rr1);

	int ans2=query(a[t].R,M+1,R,M+1,rr,ll1,rr1);

	return max(ans1,ans2);

}



int main()

{

	//FFF;



	n=getInt(); m=getInt();

	int i;

	for(i=1;i<=n;i++) b[i].val=getInt(),b[i].id=i,last[i]=0,next[i]=n+1;

	for(i=1;i<=n;i++)

	{

		b[i].last=last[b[i].val];

		last[b[i].val]=i;

	}

	for(i=n;i>=1;i--)

	{

		b[i].next=next[b[i].val];

		next[b[i].val]=i;

	}

	sort(b+1,b+n+1,cmp);

	int j=1;

	for(i=0;i<n;i++)

	{

		if(i) root[i]=root[i-1];

		while(j<=n&&b[j].last==i)

		{

			insert(root[i],0,n+1,b[j].next,b[j].id,b[j].val);

			j++;

		}

	}



	int ans=0;

	while(m--)

	{

		int L=getInt();

		int R=getInt();

		L=(L+ans)%n+1;

		R=(R+ans)%n+1;

		if(L>R) swap(L,R);

		ans=query(root[L-1],0,n+1,R+1,n+1,L,R);

		printf("%d\n",ans);

	}

}

 

你可能感兴趣的:(simple)