【bzoj3489】A simple rmq problem

Portal -->bzoj3489

Solution

  最近计划智力康复qwq(话说这题一年前刚刚开始写树套树的时候感觉好难啊qwq现在看其实还好也算是有进步的嘛!)

  比较重要的一步是,要将“在\([l,r]\)中只出现一次”这个条件转化成"\(nxt[x]>r\)&&\(pre[x]<l\)",其中\(nxt[x]\)表示下一个出现位置\(x\)的数的位置,\(pre[x]\)表示前一个

  然后我们就发现其实是有三个限制:

1、\(pre[x]<l\)

2、\(nxt[x]>r\)

3、最大

  那所以我们用两棵主席树套在一起就好了

​  外层的主席树按照\(pre[x]\)来顺序加点,树内按照\(nxt\)的顺序为关键字,然后对于每个节点(也就是区间啦),再开一棵主席树,以\(nxt\)为根的顺序,树内以\(val[x]\)为关键字(也就是权值线段树啦)

​  然后修改直接修改,查询的时候我们先二分一下外层主席树应该调用哪个\(rt\),也就是二分一个最大的\(pos\)满足\(pre[pos]<l\),然后\(query(rt[pos],l,r)\)即可

  想清楚了的话还是比较好写的

  有一些需要稍微注意一下的小细节

1、如果说对于那些后面已经没有与其相同的数的位置,为了方便我们将其\(nxt\)赋成\(n+1\),所以这里要注意主席树的区间应该是\([1,n+1]\)

2、查询的时候,要注意因为我们要求的是\(nxt[x]>r\),所以在查询中涉及到的范围应该是\(>\)而不是\(>=\)之类的,跟平时写线段树有那么一点点小区别稍微注意一下

  

  代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100010,M=200010,SEG=N*20;
struct Data{
	int pre,nxt,id,val;
	friend bool operator < (Data x,Data y)
	{return x.pre<y.pre;}
}a[N];
int loc[N];
int n,m,ans;
namespace NodeSeg{/*{{{*/
	int ch[SEG*20][2],mx[SEG*20],rt[SEG];
	int n,tot;
	int newnode(int pre){
		ch[++tot][0]=ch[pre][0],ch[tot][1]=ch[pre][1]; mx[tot]=mx[pre];
		return tot;
	}
	void pushup(int x){mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);}
	void _update(int pre,int &x,int lx,int rx,Data &delta){
		x=newnode(pre);
		if (lx==rx){mx[x]=delta.val;return;}
		int mid=lx+rx>>1;
		if (delta.id<=mid) _update(ch[pre][0],ch[x][0],lx,mid,delta);
		else _update(ch[pre][1],ch[x][1],mid+1,rx,delta);
		pushup(x);
	}
	void update(int pre,int x,Data delta){_update(rt[pre],rt[x],1,n,delta);}
	int _query(int x,int l,int r,int lx,int rx){
		if (mx[x]==0) return 0;
		if (l<=lx&&rx<=r) return mx[x];
		int mid=lx+rx>>1,ret=0;
		if (l<=mid) ret=max(ret,_query(ch[x][0],l,r,lx,mid));
		if (r>mid) ret=max(ret,_query(ch[x][1],l,r,mid+1,rx));
		return ret;
	}
	int query(int x,int l,int r){return _query(rt[x],l,r,1,n);}
}/*}}}*/
namespace NextSeg{/*{{{*/
	int ch[SEG][2],rt[SEG];
	int n,tot;
	int newnode(int pre,Data delta){
		ch[++tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1];
		NodeSeg::update(pre,tot,delta);
		return tot;
	}
	void _update(int pre,int &x,int lx,int rx,Data delta){
		x=newnode(pre,delta);
		if (lx==rx) return;
		int mid=lx+rx>>1;
		if (delta.nxt<=mid) _update(ch[pre][0],ch[x][0],lx,mid,delta);
		else _update(ch[pre][1],ch[x][1],mid+1,rx,delta);
	}
	void update(int x,Data delta){_update(rt[x-1],rt[x],1,n,delta);}
	int _query(int x,int l,int r,int lx,int rx){
		if (r<lx&&rx<=n) return NodeSeg::query(x,l,r);
		int mid=lx+rx>>1,ret=0;
		if (r<mid) ret=max(ret,_query(ch[x][0],l,r,lx,mid));
		ret=max(ret,_query(ch[x][1],l,r,mid+1,rx));
		return ret;
	}
	int query(int x,int l,int r){return _query(rt[x],l,r,1,n);}
}/*}}}*/
int read(){
	int ret=0; char ch=getchar();
	while (ch<'0'||ch>'9') ch=getchar();
	while ('0'<=ch&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
	return ret;
}

void prework(){
	for (int i=1;i<=n;++i) a[i].pre=0,a[i].nxt=n+1;
	for (int i=1;i<=n;++i){
		a[i].id=i;
		if (loc[a[i].val]) 
			a[loc[a[i].val]].nxt=i,a[i].pre=loc[a[i].val];
		loc[a[i].val]=i;
	}
	NodeSeg::n=n+1; NextSeg::n=n+1;
}

int get_pos(int x){
	int l=1,r=n,mid,ret=l;
	while (l<=r){
		mid=l+r>>1;
		if (x<=a[mid].pre) r=mid-1;
		else l=mid+1;
	}
	return l-1;
}

int main(){/*{{{*/
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	int x,y,x1,y1,pos;
	n=read(); m=read();
	for (int i=1;i<=n;++i) a[i].val=read();
	prework();
	sort(a+1,a+1+n);
	for (int i=1;i<=n;++i)
		NextSeg::update(i,a[i]);
	for (int i=1;i<=m;++i){
		x1=read(); y1=read();
		x=min((x1+ans)%n+1,(y1+ans)%n+1);
		y=max((x1+ans)%n+1,(y1+ans)%n+1);
		pos=get_pos(x);
		ans=NextSeg::query(pos,x,y);
		printf("%d\n",ans);
	}
}/*}}}*/
posted @ 2018-07-15 16:09  yoyoball  阅读(251)  评论(0编辑  收藏  举报