本文主要是介绍[bzoj3489][kdtree]A simple rmq problem,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Description
因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
Input
第一行为两个整数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
Output
一共M行,每行给出每个询问的答案。
Sample Input
10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9
Sample Output
4
10
10
0
0
10
0
4
0
4
HINT
注意出题人为了方便,input的第二行最后多了个空格。
2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测
题解
发现kdt原来这么强大
原来想了好久可持久化线段树没想到,然后发现做不到。
然后就%了一发发现,原来还有这种操作。
设第i个元素前一个相同元素的位置是pre[i],后一个相同元素的位置是nex[i],元素值为sum[i]
对于l~r,其实就是要找一个l<=i<=r,其中sum[i]最大且pre[i]< l && nex[i]>r
建立三元组(i,pre[i],nex[i]),值即为sum[i]
那么其实就是搞一个三维空间了,三维空间内确定一个范围并找到这个范围内的最大值
切割多维空间就是kdtree啦
在kdtree里进行贪心查找并剪枝即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{int f=1,x=0;char ch=getchar();while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
struct node
{int d[3],mn[3],mx[3],lc,rc;//0 位置 1 pre 2 nex int s,id,pre,nex,smax;
}tr[110000],root;
void upd(int now)
{int lc=tr[now].lc,rc=tr[now].rc;if(lc){for(int i=0;i<3;i++)tr[now].mx[i]=max(tr[now].mx[i],tr[lc].mx[i]),tr[now].mn[i]=min(tr[now].mn[i],tr[lc].mn[i]);tr[now].smax=max(tr[now].smax,tr[lc].smax);}if(rc){for(int i=0;i<3;i++)tr[now].mx[i]=max(tr[now].mx[i],tr[rc].mx[i]),tr[now].mn[i]=min(tr[now].mn[i],tr[rc].mn[i]);tr[now].smax=max(tr[now].smax,tr[rc].smax);}
}
int cmpd;
bool cmp(node n1,node n2){return n1.d[cmpd]<n2.d[cmpd];}
int bt(int l,int r,int d)
{int mid=(l+r)/2;cmpd=d;int now=mid;nth_element(tr+l,tr+mid,tr+r+1,cmp);tr[now].smax=tr[now].s;if(l<mid)tr[now].lc=bt(l,mid-1,(d+1)%3);if(mid<r)tr[now].rc=bt(mid+1,r,(d+1)%3);upd(now);return now;
}
int ql,qr,ans;
bool chk(int now)
{if(now==0)return false;if(tr[now].mx[0]<ql || tr[now].mn[0]>qr)return false;if(tr[now].mn[1]>=ql || tr[now].mx[2]<=qr)return false;return true;
}
void fd(int now)
{if(tr[now].mn[0]>=ql && tr[now].mx[0]<=qr && tr[now].mx[1]<ql && tr[now].mn[2]>qr){ans=max(ans,tr[now].smax);return ;}if(tr[now].id>=ql && tr[now].id<=qr && tr[now].pre<ql && tr[now].nex>qr)ans=max(ans,tr[now].s);int sx=tr[tr[now].lc].smax,sy=tr[tr[now].rc].smax;if(sx>sy){if(tr[now].lc && sx>ans && chk(tr[now].lc))fd(tr[now].lc);if(tr[now].rc && sy>ans && chk(tr[now].rc))fd(tr[now].rc);}else{if(tr[now].rc && sy>ans && chk(tr[now].rc))fd(tr[now].rc);if(tr[now].lc && sx>ans && chk(tr[now].lc))fd(tr[now].lc);}
}
int n,m,a[110000];
int P[110000],N[110000],lastans;
int main()
{n=read();m=read();for(int i=1;i<=n;i++)a[i]=read();for(int i=1;i<=n;i++){tr[i].pre=tr[i].mn[1]=tr[i].mx[1]=tr[i].d[1]=P[a[i]];P[a[i]]=i;}memset(N,63,sizeof(N));for(int i=n;i>=1;i--){tr[i].nex=tr[i].mn[2]=tr[i].mx[2]=tr[i].d[2]=N[a[i]];N[a[i]]=i;}for(int i=1;i<=n;i++)tr[i].s=a[i],tr[i].id=tr[i].d[0]=tr[i].mx[0]=tr[i].mn[0]=i;int root=bt(1,n,0);lastans=0;while(m--){int x=read(),y=read();ql=min((x+lastans)%n+1,(y+lastans)%n+1);qr=max((x+lastans)%n+1,(y+lastans)%n+1);ans=0;fd(root);printf("%d\n",ans);lastans=ans;}return 0;
}
这篇关于[bzoj3489][kdtree]A simple rmq problem的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!