bzoj3489 A simple rmq problem KD树

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82901540

Description


因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)
第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N
再下面M行,每行两个整数x,y,
询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):
l=min((x+lastans)mod n+1,(y+lastans)mod n+1);
r=max((x+lastans)mod n+1,(y+lastans)mod n+1);
Lastans表示上一个询问的答案,一开始lastans为0

Solution


月考被踩爆了呀QAQ

考虑把每一个数字相同的前一个位置L[i]、后一个位置R[i]找出来,显然只有询问区间[l,r]满足L[i]<=l<=i<=r<=R[i]的时候a[i]才有可能被算,然后我就不会做了

题解说可以把(L[i],R[i],i)看成i这个点在三维空间中的坐标,那么我们实际上要找一个立方体中的最大值。这个可以树套树套树(雾)、树套树、树套堆、KD树来做,这里写了KD树的做法
注意KD树的剪枝,写了剪枝才不是暴力

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))

const int N=200005;

struct treeNode {
	int l,r,p[3],mn[3],mx[3],max,v;

	bool operator <=(treeNode b) const {
		treeNode a=*this;
		return (a.p[0]<=b.p[0])&&(a.p[1]<=b.p[1])&&(a.p[2]<=b.p[2]);
	}
} t[N];

int L[N],R[N],rec[N],a[N],D;
int ql,qr,ans;

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

void push_up(int x) {
	rep(i,0,2) {
		if (t[x].l) {
			t[x].mx[i]=std:: max(t[x].mx[i],t[t[x].l].mx[i]);
			t[x].mn[i]=std:: min(t[x].mn[i],t[t[x].l].mn[i]);
		}
		if (t[x].r) {
			t[x].mx[i]=std:: max(t[x].mx[i],t[t[x].r].mx[i]);
			t[x].mn[i]=std:: min(t[x].mn[i],t[t[x].r].mn[i]);
		}
	}
	if (t[x].l) t[x].max=std:: max(t[x].max,t[t[x].l].max);
	if (t[x].r) t[x].max=std:: max(t[x].max,t[t[x].r].max);
}

bool check(int x) {
	if (t[x].mn[0]>=ql) return 0;
	if (t[x].mx[2]<=qr) return 0;
	if (t[x].mn[1]>qr||t[x].mx[1]<ql) return 0;
	return 1;
}

void query(int now) {
	if (t[now].p[0]<ql&&ql<=t[now].p[1]&&t[now].p[1]<=qr&&qr<t[now].p[2]) ans=std:: max(ans,t[now].v);
	if (t[now].l) {
		if (check(t[now].l)&&t[t[now].l].max>ans) query(t[now].l);
	}
	if (t[now].r) {
		if (check(t[now].r)&&t[t[now].r].max>ans) query(t[now].r);
	}
}

bool cmp(treeNode a,treeNode b) {
	return a.p[D]<b.p[D];
}

int build(int l,int r,int d) {
	int mid=(l+r)>>1; D=d;
	std:: nth_element(t+l,t+mid,t+r+1,cmp);
	rep(i,0,2) t[mid].mn[i]=t[mid].mx[i]=t[mid].p[i];
	if (l<mid) t[mid].l=build(l,mid-1,(d+1)%3);
	if (mid<r) t[mid].r=build(mid+1,r,(d+1)%3);
	push_up(mid); return mid;
}

int main(void) {
	// freopen("data.in","r",stdin);
	int n=read(),m=read();
	rep(i,1,n) a[i]=read();
	rep(i,1,n) {
		L[i]=rec[a[i]];
		rec[a[i]]=i;
	}
	rep(i,1,n) rec[i]=n+1;
	drp(i,n,1) {
		R[i]=rec[a[i]];
		rec[a[i]]=i;
	}
	rep(i,1,n) {
		t[i].p[0]=t[i].mn[0]=t[i].mx[0]=L[i];
		t[i].p[1]=t[i].mn[1]=t[i].mx[1]=i;
		t[i].p[2]=t[i].mn[2]=t[i].mx[2]=R[i];
		t[i].max=t[i].v=a[i];
	}
	int root=build(1,n,0);
	for (int lastans=0,x,y;m--;) {
		x=read(),y=read(),ql=(x+lastans)%n+1,qr=(y+lastans)%n+1;
		if (qr<ql) std:: swap(ql,qr);
		ans=0; query(root);
		printf("%d\n", ans); lastans=ans;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/82901540