BZOJ3489:A simple rmq problem

浅谈\(K-D\) \(Tree\)https://www.cnblogs.com/AKMer/p/10387266.html

题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=3489

主席树套主席树写法:https://www.cnblogs.com/AKMer/p/10197640.html

可以同主席树套主席树写法一样,用可持久化搞掉第一维\(pre\),然后对于\(n\)个点\((id,nxt)\),直接查询区间\([l,r][r+1,n+1]\)内的最大值即为答案。

时间复杂度:\(O(nlogn+m\sqrt{n})\)

空间复杂度:\(O(nlogn)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define bo11 p[u].mx[0]<x1||p[u].mn[0]>x2
#define bo12 p[u].mx[1]<y1||p[u].mn[1]>y2
#define bo21 x1<=p[u].mn[0]&&p[u].mx[0]<=x2
#define bo22 y1<=p[u].mn[1]&&p[u].mx[1]<=y2
#define bo31 x1<=p[u].c[0]&&p[u].c[0]<=x2
#define bo32 y1<=p[u].c[1]&&p[u].c[1]<=y2

const int maxn=1e5+5,inf=2e9;

int pos[maxn],tmp[maxn];
int n,m,pps,lstans,x1,x2,y1,y2;

int read() {
	int x=0,f=1;char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
	return x*f;
}

struct data {
	int v,pre,nxt,id;

	bool operator<(const data &a)const {
		return pre<a.pre;
	}
}a[maxn];

struct kd_tree {
	int tot,root[maxn];

	struct point {
		int ls,rs,mxv,val,d;
		int c[2],mn[2],mx[2];

		bool operator<(const point &a)const {
			if(c[pps]==a.c[pps])return c[0]<a.c[0];
			return c[pps]<a.c[pps];
		}
	}p[maxn*18];

	int build(int l,int r,int d) {
		int mid=(l+r)>>1,u=mid;pps=d;
		nth_element(p+l,p+mid,p+r+1);
		if(l<mid)p[u].ls=build(l,mid-1,d^1);
		if(r>mid)p[u].rs=build(mid+1,r,d^1);
		p[u].d=d;return u;
	}

	void update(int u) {
		int ls=p[u].ls,rs=p[u].rs;
		int mxv=max(p[ls].mxv,p[rs].mxv);
		p[u].mxv=max(mxv,p[u].val);
		for(int i=0;i<2;i++) {
			int mn=min(p[ls].mn[i],p[rs].mn[i]);
			p[u].mn[i]=min(p[u].mn[i],mn);
			int mx=max(p[ls].mx[i],p[rs].mx[i]);
			p[u].mx[i]=max(p[u].mx[i],mx);
		}
	}

	void insert(int lst,int &u,int x,int y,int v) {
		u=++tot,p[u]=p[lst];
		if(p[u].c[0]==x&&p[u].c[1]==y) {
			p[u].val=v;
			p[u].mn[0]=p[u].mx[0]=x;
			p[u].mn[1]=p[u].mx[1]=y;
			update(u);return;
		}
		int O=p[u].d,num=O?y:x;
		if((num<p[u].c[O])||(num==p[u].c[O]&&x<p[u].c[0]))
			insert(p[lst].ls,p[u].ls,x,y,v);
		else insert(p[lst].rs,p[u].rs,x,y,v);
		update(u);
	}

	void prepare() {
		p[0].mn[0]=p[0].mn[1]=inf;
		p[0].mx[0]=p[0].mx[1]=-inf;
		for(int i=1;i<=n;i++) {
			p[i].mn[0]=p[i].mn[1]=inf;
			p[i].mx[0]=p[i].mx[1]=-inf;
			p[i].c[0]=a[i].id;
			p[i].c[1]=a[i].nxt;
			p[i].mxv=-inf;
		}
		root[0]=build(1,n,0);
		for(int i=1;i<=n;i++) {
			insert(root[i-1],root[i],a[i].id,a[i].nxt,a[i].v);
		}
	}

	void find(int u) {
		if(p[u].mxv<lstans)return;
		if(bo11||bo12)return;
		if(bo21&&bo22) {lstans=max(lstans,p[u].mxv);return;}
		if(bo31&&bo32) lstans=max(lstans,p[u].val);
		if(p[u].ls)find(p[u].ls);
		if(p[u].rs)find(p[u].rs);
	}
}T;

int main() {
	T.tot=n=read(),m=read();
	for(int i=1;i<=n;i++) {
		a[i].v=read(),a[i].id=i;
		a[i].pre=pos[a[i].v],pos[a[i].v]=i;
	}
	for(int i=1;i<=n;i++)pos[i]=n+1;
	for(int i=n;i;i--)
		a[i].nxt=pos[a[i].v],pos[a[i].v]=i;
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)tmp[i]=a[i].pre;
	T.prepare();
	for(int i=1;i<=m;i++) {
		int l=(read()+lstans)%n+1,r=(read()+lstans)%n+1;
		if(r<l)swap(l,r);x1=l,x2=r,y1=r+1,y2=n+1;
		int pos=lower_bound(tmp+1,tmp+n+1,l)-tmp-1;
		lstans=-inf,T.find(T.root[pos]);
		if(lstans==-inf)lstans=0;
		printf("%d\n",lstans);
	}
	return 0;
}
posted @ 2019-02-20 20:35  AKMer  阅读(170)  评论(0编辑  收藏  举报