BZOJ3489 A simple rmq problem(KD树代替可持久化树套树)

题面:https://www.lydsy.com/JudgeOnline/problem.php?id=3489

 

 

 

 

 

 

 

题解

可持久化树套树太难写了,直接用KD树水过去。。。

对于每个点,找到前一个跟它的值相同的点pre,与后一个跟它的值相同的点nxt

那么点 i 能够更新答案的充要条件就是:l<=i<=r  ,prei<l  ,  nxti>r

然后把一个点的坐标设为3维,分别为(i,prei,nxti)

写一个支持查询最大值的3D树就可以了

代码:(时间复杂度较高O(n^{\frac{5}{3}})     24548ms

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define lc ch[i][0]
#define rc ch[i][1]
const int INF=1000000000;
int D;
int ch[N][2],rt,tot;
int tmp[N],cnt;
int a[N][3],mi[N][3],mx[N][3];
int mxx[N],val[N];
int qmi[3],qmx[3];
int pre[N],nxt[N],tong[N];
inline void pushup(int i)
{
	for(int j=0;j<3;j++){
		mi[i][j]=min(min(mi[lc][j],mi[rc][j]),a[i][j]);
		mx[i][j]=max(max(mx[lc][j],mx[rc][j]),a[i][j]);
	}
	mxx[i]=max(max(mxx[lc],mxx[rc]),val[i]);
}
inline bool cmp(const int &x,const int &y){return a[x][D]<a[y][D];}
void build(int &i,int l,int r,int d)
{
	int mid=(l+r)>>1;D=d;
	nth_element(tmp+l,tmp+mid,tmp+r+1,cmp);
	i=tmp[mid];lc=rc=0;
	if(l<mid)build(lc,l,mid-1,(d+1)%3);
	if(r>mid)build(rc,mid+1,r,(d+1)%3);
	pushup(i);
}
int ans;//long long con;
void query(int &i)
{
	//con++;
	if(!i)return;
	if(mxx[i]<=ans)return;
	if(mx[i][0]<qmi[0]||qmx[0]<mi[i][0]
	||mx[i][1]<qmi[1]||qmx[1]<mi[i][1]
	||mx[i][2]<qmi[2]||qmx[2]<mi[i][2])
	return;
	
	if(qmi[0]<=mi[i][0]&&mx[i][0]<=qmx[0]
	&&qmi[1]<=mi[i][1]&&mx[i][1]<=qmx[1]
	&&qmi[2]<=mi[i][2]&&mx[i][2]<=qmx[2])
	{ans=max(ans,mxx[i]);return;}
	
	if(qmi[0]<=a[i][0]&&a[i][0]<=qmx[0]
	&&qmi[1]<=a[i][1]&&a[i][1]<=qmx[1]
	&&qmi[2]<=a[i][2]&&a[i][2]<=qmx[2])
	ans=max(ans,val[i]);
	
	query(lc);query(rc);
}

//#include<ctime>
//double c1;
int main()
{
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	//c1=clock();
	
	mi[0][0]=mi[0][1]=mi[0][2]=INF;
	mx[0][0]=mx[0][1]=mx[0][2]=-INF;
	int n,m,i,l,r,x,y;
	n=gi();m=gi();
	for(i=1;i<=n;i++){
		x=gi();val[i]=x;
		pre[i]=tong[x];
		nxt[tong[x]]=i;
		tong[x]=i;
	}
	for(i=1;i<=n;i++)if(tong[i])
		nxt[tong[i]]=n+1;
	for(i=1,tot=n;i<=n;i++){
		a[i][0]=i;a[i][1]=pre[i];a[i][2]=nxt[i];
		tmp[++cnt]=i;
	}
	build(rt,1,cnt,0);
	for(i=1;i<=m;i++){
		x=gi();y=gi();
		l=min((x+ans)%n+1,(y+ans)%n+1);
		r=max((x+ans)%n+1,(y+ans)%n+1);
		//l=x;r=y;
		ans=0;
		qmi[0]=l;qmx[0]=r;
		qmi[1]=-INF;qmx[1]=l-1;
		qmi[2]=r+1;qmx[2]=INF;
		query(rt);
		printf("%d\n",ans);
	}
	
	//freopen("CON","w",stdout);
	//printf("%.3fs\n",(clock()-c1)/1000);
	//printf("%lld\n",con);
}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值