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
",ans);
	}
}
原文地址:https://www.cnblogs.com/jianglangcaijin/p/4063608.html