由于某些原因,我先打了一个错误的树套树,后来打起了$k-d$。接着因不明原因在思路上被卡了很久,在今天中午蹲坑时恍然大悟......

对于一个数字$a_i$,我们可以用一组三维坐标$(i,pre,nxt)$来表示,其中$i$表示该数字下标,$pre$表示在区间$[1,i)$中满足$a[j]=a[i]$的最大$j$,若不存在,则$pre=0$。$nxt$表示在区间$(i,n]$中满足$a[j]=a[i]$的最小$j$,若不存在,则$nxt=n+1$。

接着我们种一棵3-d树去存储这n个点。对于任意一个节点,需存储该节点的数字,以该节点为根的字数中最大的数字,每一维的最小值和最大值。对于一组询问$[l,r]$,答案即为满足第一维在区间$[l,r]$,第二维在区间$[0,l)$,第三维在区间$(r,n+1)$中的所有点上的最大数字。在查询时,直接按照$k-d$的正常查询策略更新答案即可。

时间复杂度:$O(n log n+n^\frac{5}{3})$

警告:若采用此方法,此题建议各位加一个微小的剪枝:假定当前所得到的最大答案为$ans$,若当前访问的字树中最大答案$≤ans$,直接跳过这棵字树即可。(借助该方法极限数据耗时从17.5s降低至1.4s)

 #include<bits/stdc++.h>
#define M 210000
using namespace std;
int n,m,D,root;
struct kd{
int a[],max[],min[],now,ans,l,r;
kd(){a[]=a[]=a[]=now=l=r=;min[]=min[]=min[]=;}
kd(int xx,int yy,int zz,int kk){a[]=xx;a[]=yy;a[]=zz;now=kk;}
friend bool operator <(kd a,kd b){
return a.a[D]<b.a[D];
}
}a[M];
void upd(kd &x,kd &y){
for(int i=;i<;i++)
x.max[i]=max(x.max[i],y.max[i]),
x.min[i]=min(x.min[i],y.min[i]);
}
inline int nx(int d){if(d==) return ; return d+;}
void build(int &x,int l,int r,int d){
if(l>r) return; int mid=(l+r)>>;
D=d; nth_element(a+l,a+mid,a+r+); x=mid;
for(int i=;i<;i++) a[x].max[i]=a[x].min[i]=a[x].a[i];
build(a[x].l,l,mid-,nx(d));
build(a[x].r,mid+,r,nx(d));
upd(a[x],a[a[x].l]); upd(a[x],a[a[x].r]);
a[x].ans=max(a[x].now,max(a[a[x].l].ans,a[a[x].r].ans));
}
int ans=;
void query(int x,int l,int r){
if(x==||ans>=a[x].ans||r<a[x].min[]||a[x].max[]<l||l-<a[x].min[]||a[x].max[]<r+) return;
if(l<=a[x].min[]&&a[x].max[]<=r&&a[x].max[]<l&&r<a[x].min[])
{ans=max(ans,a[x].ans); return;}
if(l<=a[x].a[]&&a[x].a[]<=r&&a[x].a[]<l&&r<a[x].a[]) ans=max(ans,a[x].now);
query(a[x].l,l,r); query(a[x].r,l,r);
}
int last[M]={};
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
int x; scanf("%d",&x);
a[i].a[]=i; a[i].now=x;
a[i].a[]=last[x];
a[last[x]].a[]=i;
last[x]=i;
}
for(int i=;i<=n;i++) if(a[i].a[]==) a[i].a[]=n+;
build(root,,n,);
while(m--){
int x,y,l,r; scanf("%d%d",&x,&y);
l=(x+ans)%n+; r=(y+ans)%n+; if(l>r) swap(l,r);
ans=; query(root,l,r);
printf("%d\n",ans);
}
}

【bzoj3489】 A simple rmq problem k-d树的更多相关文章

  1. bzoj3489: A simple rmq problem (主席树)

    //========================== 蒟蒻Macaulish:http://www.cnblogs.com/Macaulish/  转载要声明! //=============== ...

  2. bzoj3489 A simple rmq problem 可持久化树套树

    先预处理出两个个数组pre,next.pre[i]表示上一个与i位置数字相同的位置,若不存在则设为0:next[i]表示下一个与i位置数字相同的位置,若不存在则设为n+1.那么一个满足在区间[L,R] ...

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

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

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

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

  5. BZOJ3489: A simple rmq problem

    设$i$的前驱为$p_i$,后继为$q_i$,把询问看成点$(L,R)$,有贡献的$i$满足$L\in(p_i,i]$且$R\in[i,q_i)$,询问的就是覆盖这个点的矩形的最大值.那么可以用可持久 ...

  6. 【kd-tree】bzoj3489 A simple rmq problem

    Orz zyf教给蒟蒻做法 蒟蒻并不会这题正解……(可持久化树套树?...Orz 对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足(pre ...

  7. BZOJ3489 A simple rmq problem K-D Tree

    传送门 什么可持久化树套树才不会写呢,K-D Tree大法吼啊 对于第\(i\)个数,设其前面最后的与它值相同的位置为\(pre_i\),其后面最前的与它值相同的位置为\(aft_i\),那么对于一个 ...

  8. 【BZOJ3489】A simple rmq problem

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

  9. bzoj 3489: A simple rmq problem k-d树思想大暴力

    3489: A simple rmq problem Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 551  Solved: 170[Submit][ ...

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

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

随机推荐

  1. php-生成数据库设计文档

    在线以及提供下载数据库设计文档 $dbserver = "192.168.128.190:42578"; $dbusername = "root"; $dbpa ...

  2. HTTP Error 403.14问题处理

    打开目录浏览后,点击启用.

  3. git将本地仓库强制替换掉远程仓库

    $ git remote add origin <url> $ git push --force --set-upstream origin master

  4. Linux学习--2

    字符串 字符串可以用单引号,也可以用双引号,也可以不用引号.单双引号的区别跟PHP类似 单引号字符串的限制:单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的:单引号字串中不能出现单引号(对 ...

  5. HDU 2504 又见GCD (最大公因数+暴力)

    题意:是中文题. 析:a和c的最大公因数是b,也就是说,a和c除了b就没有公因数了.再说就是互质了. 所以先把a除以b,然后一个暴力n,满足gcd(a, n) =1,就结束,就是n倍的c. 代码如下: ...

  6. SPSS-比较均值-独立样本T检验 案例解析

    在使用SPSS进行单样本T检验时,很多人都会问,如果数据不符合正太分布,那还能够进行T检验吗?而大样本,我们一般会认为它是符合正太分布的,在鈡型图看来,正太分布,基本左右是对称的,一般具备两个参数,数 ...

  7. 20155231 2016-2017-2 《Java程序设计》第9周学习总结

    20155231 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 第十六章:整合数据库 Metadata即"诠读数据的数据",数据库是用来 ...

  8. Android类装载器DexClassLoader的简单使用-----制作android插件的前奏

    声明:此篇文章借鉴<android内核剖析>整理得来. 一.装载器简介 “类装载器”(ClassLoader),顾名思义,就是用来动态装载class文件的.标准的Java SDK中有个Cl ...

  9. linux下怎样用c语言调用shell命令

    C程序调用shell脚本共同拥有三种法子 :system().popen().exec系列数call_exec1.c , system() 不用你自己去产生进程.它已经封装了,直接增加自己的命令 ex ...

  10. D3 API总览

    D3图形库API参考 https://github.com/d3/d3/wiki/API--%E4%B8%AD%E6%96%87%E6%89%8B%E5%86%8C d3 官网 API https:/ ...