浅谈\(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. Qt移植对USB鼠标键盘、触摸屏的支持

    .USB键盘 经过一番搜索,发现对Qt键盘的支持主要关系到两个方面: 1. 键盘类型确定: 4.7以前的Qt版本,如果是PS2圆孔键盘,Qt编译时需加上选项:-qt-kbd-vr41xx(未测试):如 ...

  2. mysql下merge分表

    1.merge简介分表就是把N条记录的表,分成若干个分表,各个分表记录的总和仍为N. 分表的方法有很多,用merge来分表,是最简单的一种方式.merge是mysql的一种存储引擎,它把一组MyISA ...

  3. PHP类的变量与成员,及其继承、访问与重写要注意的问题

    PHP的类及其实例: <?php ?>  后期静态绑定:为了避免子类重写静态属性后,使用继承来的方法仍然方法父类的静态属性,PHP5.3增加了一个新的语法,后期静态绑定,使用static关 ...

  4. INSPIRED启示录 读书笔记 - 第1章 关键角色及其职责

    现代软件产品团队 1.产品经理的主要职责分为两项:评估产品机会和定义要开发的产品 2.用户体验设计师(由多种角色组成,这里面最关键的是交互设计师)      交互设计师负责深入理解目标用户,设计有价值 ...

  5. python的pexpect详解

    Pexpect 是一个用来启动子程序并对其进行自动控制的纯 Python 模块. Pexpect 可以用来和像 ssh.ftp.passwd.telnet 等命令行程序进行自动交互.继第一部分< ...

  6. winform获取文件路径

    1.取得控制台应用程序的根目录方法     方法1.Environment.CurrentDirectory 取得或设置当前工作目录的完整限定路径     方法2.AppDomain.CurrentD ...

  7. 泛型学习第一天:List与IList的区别 (三)

    已经有很多人讨论过IList和List的区别,恩,我也赞同其中的一些观点,其实他们二者也是有优有劣的,看你着重用在哪个方面,先贴一下我赞同的意见,基本上也都是网友们总结的. 首先IList 泛型接口是 ...

  8. 【转】Android PullToRefresh (ListView GridView 下拉刷新) 使用详解

    最近项目用到下拉刷新,上来加载更多,这里对PullToRefresh这控件进行了解和使用. 以下内容转载自:http://blog.csdn.net/lmj623565791/article/deta ...

  9. qemu-kvm 代码分析

    qemu-kvm 代码分析 虚拟机组成 实际上面所说计算机组成比较笼统,实际处理器,存储器,输入与设备种类繁多,     -   i440FX host PCI bridge and PIIX3 PC ...

  10. review21

    Class是java.lang包中的类,该类的实例可以帮助程序创建其他类的实例或者取得其他类的对象的内部信息. 参考代码如下所示: package pack07; import java.util.D ...