题意:给定数列\(a[1...n]\),\(Q\)次查询\([L,R]\)中只出现一次的最大值

这道题的做法比较劲..

对每个元素构造三维空间的点\((i,pre[i],next[i])\),查询\([L,R]\)可以转换为查询\((L≤x≤R,y<L,z>R)\)的区间的最大值

就是说前一个和后一个都不在这个范围内的值

除此以外要注意剪枝!直接按照上面的思路码是会T的

比如随机乱跑,估计一下子树的\(max\)是否比当前答案更优,或者估价边界是否应该搜索(后者我没有写,也就慢个4s..)

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define rrep(i,j,k) for(register int i=j;i>=k;i--)
#define erep(i,u) for(register int i=head[u];~i;i=nxt[i])
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
#define printbk(a) printf("%lld ",(ll)(a))
using namespace std;
const int MAXN = 1e5+11;
const int INF = 0x7fffffff;
typedef long long ll;
ll read(){
ll x=0,f=1;register 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;
}
int D;
struct Point{
int x[3],val;
bool operator < (const Point &rhs) const{
return x[D]<rhs.x[D];
}
};
struct KD{
int son[MAXN][2],lx[MAXN][3],rx[MAXN][3];
int size[MAXN];
int mx[MAXN];
Point p[MAXN];
int root,tot;
void pu(int o){
mx[o]=p[o].val;
int lc=son[o][0],rc=son[o][1];
rep(i,0,2){
lx[o][i]=rx[o][i]=p[o].x[i];
if(lc){
if(mx[lc]>mx[o]) mx[o]=mx[lc];
if(lx[lc][i]<lx[o][i]) lx[o][i]=lx[lc][i];
if(rx[lc][i]>rx[o][i]) rx[o][i]=rx[lc][i];
}
if(rc){
if(mx[rc]>mx[o]) mx[o]=mx[rc];
if(lx[rc][i]<lx[o][i]) lx[o][i]=lx[rc][i];
if(rx[rc][i]>rx[o][i]) rx[o][i]=rx[rc][i];
}
}
size[o]=1+size[lc]+size[rc];
}
void init(int n){
root=D=0; tot=n;
}
inline bool inside(int o,int l,int r){
return lx[o][2]>r&&rx[o][1]<l&&lx[o][0]>=l&&rx[o][0]<=r;
}
inline bool outside(int o,int l,int r){
return lx[o][0]>r||rx[o][0]<l||lx[o][1]>=l||rx[o][2]<=r;
}
inline bool in(int o,int l,int r){
int x=p[o].x[0],y=p[o].x[1],z=p[o].x[2];
return x>=l&&x<=r&&y<l&&z>r;
}
/*注意必要的剪枝!*/
// ll query(int o,int l,int r){// l<=x<=r && y<l && z>r //上一个<l 下一个>r
// if(!o) return 0;
// if(inside(o,l,r)) return mx[o];
// if(outside(o,l,r)) return 0;
// ll res=0;
// if(in(o,l,r)) res=p[o].val;
// return max(res,max(query(son[o][0],l,r),query(son[o][1],l,r)));
// }
/*上面这个会T*/
int ANS;
void query(int o,int l,int r){
if(!o) return;
if(inside(o,l,r)){
if(ANS<mx[o]) ANS=mx[o];
return;
}
if(outside(o,l,r)) return;
if(in(o,l,r)&&ANS<p[o].val) ANS=p[o].val;
int lc=son[o][0], rc=son[o][1];
if(mx[lc]>mx[rc]){
if(mx[lc]>ANS) query(lc,l,r); //其实还可以对左右子树多加一个估价函数
if(mx[rc]>ANS) query(rc,l,r);
}else{
if(mx[rc]>ANS) query(rc,l,r);
if(mx[lc]>ANS) query(lc,l,r);
}
}
int build(int now,int l,int r){
int mid=l+r>>1; son[mid][0]=son[mid][1]=0;
D=now; nth_element(p+l,p+mid,p+r+1);
mx[mid]=p[mid].val; size[mid]=1;
rep(i,0,2) lx[mid][i]=rx[mid][i]=p[mid].x[i];
if(l<mid) son[mid][0]=build((now+1)%3,l,mid-1);
if(r>mid) son[mid][1]=build((now+1)%3,mid+1,r);
pu(mid); return mid;
}
ll query(int l,int r){
ANS=0;
query(root,l,r);
return ANS;
}
}kd;
int a[MAXN],pre[MAXN],nxt[MAXN];
int main(){
ll n,m,lastans=0;
while(cin>>n>>m){
rep(i,1,n) pre[i]=-1;
rep(i,1,n) nxt[i]=n+1;
rep(i,1,n) a[i]=read();
rep(i,1,n){
kd.p[i].x[0]=i;
kd.p[i].val=a[i];
kd.p[i].x[1]=pre[a[i]];
pre[a[i]]=i;
}
rrep(i,n,1){
kd.p[i].x[2]=nxt[a[i]];
nxt[a[i]]=i;
}
kd.init(n); kd.root=kd.build(0,1,n);
rep(i,1,m){
int x=read();
int y=read();
int l=min((x+lastans)%n+1,(y+lastans)%n+1);
int r=max((x+lastans)%n+1,(y+lastans)%n+1);
ll res=kd.query(l,r);
println(res);
lastans=res;
}
}
return 0;
}

BZOJ - 3489 KD树 范围计数 空间思维转换的更多相关文章

  1. BZOJ - 4066 KD树 范围计数 暴力重构

    题意:单点更新,大矩阵(\(n*n,n≤10^5\))求和 二维的KD树能使最坏情况不高于\(O(N\sqrt{N})\) 核心在于query时判断当前子树维护的区间是否有交集/当前子节点是否在块中, ...

  2. BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

    知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! -------------------------------------- ...

  3. bzoj 1211: [HNOI2004]树的计数 -- purfer序列

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MB Description 一个有n个结点的树,设它的结点分别为v1, v2, ...

  4. BZOJ - 2648 KD树 最近点查询

    省赛后躺尸几天又回来更新了,内容是说好的KD树.. 具体操作从代码中感受一下 感觉已经把KD树尽量封装好了(虽然全局的D看着极不顺眼) 需要注意的是估值函数的判断条件 #include<bits ...

  5. BZOJ 1211 HNOI2004 树的计数 Prufer序列

    题目大意:给定一棵树中全部点的度数,求有多少种可能的树 Prufer序列.详细參考[HNOI2008]明明的烦恼 直接乘会爆long long,所以先把每一个数分解质因数.把质因数的次数相加相减.然后 ...

  6. bzoj 3244: [Noi2013]树的计数

    Description 我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序.两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同, ...

  7. BZOJ 1211[HNOI2004]树的计数 - prufer数列

    描述 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要输出满足d(vi) ...

  8. 【刷题】BZOJ 1211 [HNOI2004]树的计数

    Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, -, dn,编程需要 ...

  9. bzoj 1211: [HNOI2004]树的计数

    prufer的应用.. 详细见这篇博客:https://www.cnblogs.com/dirge/p/5503289.html import java.math.BigInteger; import ...

随机推荐

  1. Ubuntu无法安装rpm包,ubuntu RPM should not be used directly install RPM packages, use Alien instead!

    Ubuntu无法安装rpm包,ubuntu RPM should not be used directly install RPM packages, use Alien instead! 简单来说, ...

  2. realsense and Mask_RCNN

    ###################librealsense and Mask_RCNN cd RealSennse/librealsense2018091501/librealsense/wrap ...

  3. 什么是Kali Linux?

    什么是Kali Linux? Kali Linux是一个基于Debian的Linux发行版,旨在实现高级渗透测试和安全审计.Kali包含数百种工具,适用于各种信息安全任务,如渗透测试,安全研究,计算机 ...

  4. boost 错误报告

    #include <Windows.h> #include <boost/asio.hpp> 编译器会报错,fatal error C1189: #error :  WinSo ...

  5. NOIP2018 解题笔记

    D1T1 铺设道路 在场上并没有想到积木大赛这道原题. 差分之后可以把在$[l, r]$这段区间$ - 1$变成在$l$处$ - 1$,在$r + 1$处$ + 1$,然后最终目标是使$\forall ...

  6. Java基础语法(二)<运算符>

    运算符: 下面的都是相关的练习: 1.键盘录入一个三位整数数,请分别获取该三位数上每一位的数值 import java.util.Scanner; public class Test02 { publ ...

  7. Monkey基础命令

    最近一直在看关于自动化测试的文章和工具,这是之前学习monkey的一些知识,想总结一下,方便以后查看,当然也可以提供一些参考.monkey 适合做压力测试,我们可以发送命令让它自己运行,并且指定运行动 ...

  8. (转)15个非常棒的jQuery无限滚动插件【瀑布流效果】

    原文地址:http://www.cnblogs.com/lyw0301/archive/2013/06/19/3145084.html 现在,最热门的网站分页趋势之一是jQuery的无限滚动(也即瀑布 ...

  9. SQLServer备份恢复助手(太强大了!)

    下载地址: http://download.csdn.net/detail/gguozhenqian/8105779

  10. SOA IN Real World

    微软发布了一个名为“真实世界里的面向服务架构(SOA)”的电子书.这本书表达了微软对面向服务架构的观点,并包括了数个展示如何用微软产品和技术实现SOA的真实案例.书中解释到,SOA的功能型架构本身是松 ...