浅谈\(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. Linux虚拟内存管理(glibc)

    转:https://blog.csdn.net/tengxy_cloud/article/details/53067396 https://www.cnblogs.com/purpleraintear ...

  2. 20145210姚思羽《网络对抗》MSF基础应用实验

    20145210姚思羽<网络对抗>MSF基础应用实验 实验后回答问题 1.用自己的话解释什么是exploit,payload,encode. exploit就是进行攻击的那一步 paylo ...

  3. linux虚拟机ping通主机

    右键虚拟机,选择网络适配器,设置为桥接模式.然后关闭主机防火墙,ping就行了(一直ping是没有参数的)

  4. Python 循环语句(while, for)

    # while的使用 # 要注意些循环的时候,要考虑好循环的结束 # 考虑循环结束的方法有2种: # 1.考虑在循环体里改变while 的条件 # 2.在循环体通过break 语句跳出循环 # 方法1 ...

  5. mysql一次运行多个SQL文件

    在文件 batch.sql 中写下多个SQL文件 source file1.SQLsource file2.SQLsource file3.SQL 然后运行 source batch.sql

  6. js正则表达式验证(化繁为简)

    以前用js写正则表达式验证,每一个文本框后面都要添加一个onblur函数,验证的信息少,也没体会到有多繁琐,这次项目中的页面比较多,页面中的信息也比较多,如果每个文本框都加一个验证函数的话,js验证代 ...

  7. 逆向破解学习二之<TraceMe>

    这次在破解TraceMe的时候,我有看过别人的视频.但是我并没有按照别人思路走,而是完全安全自己的思路试了一次.结果破解成功.新手学破解,如果有不对的地方,还请指出来. 004013A0 crackm ...

  8. python练习_sed替换

    python练习_sed替换 需求: 做一个sed替换小程序,实现在windows下可以与实现linux中sed替换的功能 支持正则(re模块) 以下代码实现的功能与思路: 功能: (1)支持文件内容 ...

  9. SGU 106 The equation 扩展欧几里德

    106. The equation time limit per test: 0.25 sec. memory limit per test: 4096 KB There is an equation ...

  10. flsk-SQLALchemy

    SQLALchemy 一.介绍     SQLALchemy是一个基于Python实现的ORM框架.该框架是建立在DB API之上,使用关系对象映射进行数据库操作     简言之便就是:将类和对象转换 ...