【bzoj 3489】A simple rmq problem(KD-Tree模板)

7 篇文章 0 订阅

传送门~
作为简易的 K − d K-d Kd t r e e tree tree模板
将一个数作为一个点 ( x , y , z ) (x,y,z) (x,y,z)
x x x为该点位置, y y y为左面第一个和它一样的数的位置, z z z是右面第一个和他一样的数的位置
问题转化成,给定 l l l r r r,求一个权值最大的点,使
y &lt; l y&lt;l y<l
z &gt; r z&gt;r z>r
r = &gt; x = &gt; l r=&gt;x=&gt;l r=>x=>l
就成了在一个长方体中求一个最大的值
代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;
int num[200005],point[200005];
int pre[200005],nex[200005];
int cmpd,n,m,ans,lx,ly,root;
struct data{
	int d[3],mx[3],mn[3],val,maxn;
	int l,r;
}s[200005];
bool cmp(data r1,data r2){
	return r1.d[cmpd]<r2.d[cmpd];
}
void maintain(int now){
	int l=s[now].l,r=s[now].r;  
    for (int i=0;i<=2;i++){  
        if(l){s[now].mx[i]=max(s[now].mx[i],s[l].mx[i]);s[now].mn[i]=min(s[now].mn[i],s[l].mn[i]);}
        if(r){s[now].mx[i]=max(s[now].mx[i],s[r].mx[i]);s[now].mn[i]=min(s[now].mn[i],s[r].mn[i]);}        
    }  
    if(l) s[now].maxn=max(s[l].maxn,s[now].maxn);
    if(r) s[now].maxn=max(s[r].maxn,s[now].maxn);
}

int build(int l,int r,int d){
	if(l>r) return 0;
	d%=3;cmpd=d;
	int mid=l+r>>1;
	nth_element(s+l,s+mid,s+r+1,cmp);
	for(int i=0;i<=2;i++) s[mid].mx[i]=s[mid].mn[i]=s[mid].d[i];
	s[mid].l=build(l,mid-1,d+1);
	s[mid].r=build(mid+1,r,d+1);
	maintain(mid);
	return mid;
}
bool check(int now){
	if(s[now].mx[0]<lx || s[now].mn[0]>ly) return 0;
	if(s[now].mn[1]>=lx) return 0;
	if(s[now].mx[2]<=ly) return 0;	
	return 1;
}
void ch(int now){
	if(s[now].d[0]>=lx && s[now].d[0]<=ly && s[now].d[1]<lx && s[now].d[2]>ly) ans=max(ans,s[now].val);
	int l=s[now].l,r=s[now].r;
	if(l && s[l].maxn>ans && check(l)) ch(l);
	if(r && s[r].maxn>ans && check(r)) ch(r);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&num[i]);
	for(int i=1;i<=n;i++) {pre[i]=point[num[i]];point[num[i]]=i;}
	for(int i=1;i<=n;i++) point[i]=n+1;
	for(int i=n;i>=1;i--) {nex[i]=point[num[i]];point[num[i]]=i;}
	for(int i=1;i<=n;i++) {s[i].d[0]=i;s[i].d[1]=pre[i];s[i].d[2]=nex[i];s[i].val=num[i];s[i].maxn=num[i];}
	root=build(1,n,0);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&lx,&ly);
		lx=(lx+ans)%n+1;
		ly=(ly+ans)%n+1;
		if(lx>ly) swap(lx,ly);
		ans=0;ch(root);
		printf("%d\n",ans);	
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值