浅谈\(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;
}

BZOJ3489:A simple rmq problem的更多相关文章

  1. 【BZOJ3489】A simple rmq problem kd-tree

    [BZOJ3489]A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过 ...

  2. 【BZOJ3489】A simple rmq problem(KD-Tree)

    [BZOJ3489]A simple rmq problem(KD-Tree) 题面 BZOJ 题解 直接做肯定不好做,首先我们知道我们是一个二维平面数点,但是限制区间只能出现一次很不好办,那么我们给 ...

  3. 【BZOJ3489】A simple rmq problem

    [BZOJ3489]A simple rmq problem 题面 bzoj 题解 这个题不强制在线的话随便做啊... 考虑强制在线时怎么搞 预处理出一个位置上一个出现的相同数的位置\(pre\)与下 ...

  4. 【bzoj3489】 A simple rmq problem

    http://www.lydsy.com/JudgeOnline/problem.php?id=3489 (题目链接) 题意 在线求区间不重复出现的最大的数. Solution KDtree竟然能够处 ...

  5. 【bzoj3489】 A simple rmq problem k-d树

    由于某些原因,我先打了一个错误的树套树,后来打起了$k-d$.接着因不明原因在思路上被卡了很久,在今天中午蹲坑时恍然大悟...... 对于一个数字$a_i$,我们可以用一组三维坐标$(i,pre,nx ...

  6. 【BZOJ3489】A simple rmq problem【kd树】

    题意 给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直接输出0.我会采取一些措施强制在线. 分析 预处理 ...

  7. 【bzoj3489】A simple rmq problem 三维KD-tree

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

  8. BZOJ3489 A simple rmq problem 【可持久化树套树】*

    BZOJ3489 A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一 ...

  9. BZOJ 3489: A simple rmq problem

    3489: A simple rmq problem Time Limit: 40 Sec  Memory Limit: 600 MBSubmit: 1594  Solved: 520[Submit] ...

随机推荐

  1. 【HackerRank】Utopian tree

    The Utopian tree goes through 2 cycles of growth every year. The first growth cycle of the tree occu ...

  2. OpenGL帧缓存对象(FBO:Frame Buffer Object)

    http://blog.csdn.net/dreamcs/article/details/7691690 转http://blog.csdn.net/xiajun07061225/article/de ...

  3. PCIE phy和控制器

    转:https://wenku.baidu.com/view/a13bc1c20722192e4436f617.html 文章中的第11页开始有划分phy和控制器部分....

  4. String和StringBuilder、StringBuffer

    Java平台提供了两种类型的字符串:String和StringBuffer/StringBuilder String 只读字符串,这里的只读并不是指String类型变量无法被修改,而是指String类 ...

  5. 基于Visual c++ 2012的php扩展开发 - HelloWord!

    1.cmd进入命令行模式,并进入php-5.6.20-src/ext源代码的ext目录下输入命令php ext_skel_win32.php --extname=HelloWord,执行结果如下图: ...

  6. 各种排序算法-用Python实现

    冒泡排序 # 冒泡排序 def bubble_sort(l): length = len(l) # 外层循环 length遍,内层循环少一遍 while length: for j in range( ...

  7. poj 2762 Going from u to v or from v to u?【强连通分量缩点+拓扑排序】

    Going from u to v or from v to u? Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15812 ...

  8. UVA 11731 Ex-circles (外切圆)

    题意:给你三角形的三条边,求图中DEF的面积和阴影部分的面积. 题解:一些模板,三角形的旁切圆半径:.与 三旁心为 #include<set> #include<map> #i ...

  9. 对象存储API

    使用对象存储API步骤: 1.购买腾讯云对象存储(COS)服务 2.在腾讯云 对象存储控制台 里创建一个Bucket 3.在控制器 个人API密钥 页里获取APPID,SecretID,SecretK ...

  10. shutdown TCP 端口445

    一. 协议:TCP 端口:445 二. shutdown /m \\192.168.1.15 -s -t 60 net use \\192.168.1.15\ipc$ 密码 /user:账户 三. g ...