Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 2579  Solved: 888
[Submit][Status][Discuss]

Description

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

Input

第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)

第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N

再下面M行,每行两个整数x,y,

询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):

l=min((x+lastans)mod n+1,(y+lastans)mod n+1);

r=max((x+lastans)mod n+1,(y+lastans)mod n+1);

Lastans表示上一个询问的答案,一开始lastans为0

Output

一共M行,每行给出每个询问的答案。

Sample Input

10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9

Sample Output

4
10
10
0
0
10
0
4
0
4

HINT

注意出题人为了方便,input的第二行最后多了个空格。

2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测

Source

 
 
 
网上又没有代码,自己yy了一上午才写出来
对于这道题目,我们记$pre_i$表示$i$号位置的元素前一次出现的位置
记$nxt_i$表示$i$号位置的元素后一次出现的位置
假设询问区间为$l,r$
那么$i$号位置满足条件,当且仅当$l<=i<=r, pre_i < l, nxt_i > r$
这样我们把$i, pre_i, nxt_i$看成一个三元组
然后用K-D tree加剪纸就行了
剪纸的时候考虑三种情况
 
  • 询问区间完全包含该节点及其左右儿子,直接通过打标记统计出最大值
  • 询问区间包含该节点但不包含其左右儿子,直接统计该节点对答案的贡献
  • 询问区间与该节点及其左右儿子不重合,直接return

有了这三种剪枝,而且此题没有插入,因此复杂度为$O(mn\sqrt{n})$

#include<cstdio>
#include<cstring>
#include<algorithm>
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2)? EOF : *p1++)
using namespace std;
const int MAXN = 1e6 + ;
char buf[ << ], *p1 = buf, *p2 = buf;
inline int read() {
char c = getchar(); int x = , f = ;
while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
int N, M, root, WD;
int Ql, Qr, lastans = ;
struct Point {
int x[];
bool operator < (const Point &rhs) const{
return x[WD] < rhs.x[WD];
}
}P[MAXN];
#define ls(x) T[x].ls
#define rs(x) T[x].rs
struct KDTree {
int ls, rs, mn[], mx[], val;
Point tp;
}T[MAXN];
int a[MAXN], pre[MAXN], nxt[MAXN], happen[MAXN];
void update(int k) {
for(int i = ; i <= ; i++) {
T[k].mn[i] = T[k].mx[i] = T[k].tp.x[i];
if(ls(k)) T[k].mn[i] = min(T[ls(k)].mn[i], T[k].mn[i]), T[k].mx[i] = max(T[ls(k)].mx[i], T[k].mx[i]);
if(rs(k)) T[k].mn[i] = min(T[rs(k)].mn[i], T[k].mn[i]), T[k].mx[i] = max(T[rs(k)].mx[i], T[k].mx[i]);
}
T[k].val = max(T[k].tp.x[], T[ls(k)].val);
T[k].val = max(T[k].val, T[rs(k)].val);
}
int Build(int l, int r, int wd) {
if(l > r) return ;
int mid = l + r >> ; WD = wd;
nth_element(P + l, P + mid, P + r + );
T[mid].tp = P[mid];
ls(mid) = Build(l, mid - , (wd + ) % );
rs(mid) = Build(mid + , r, (wd + ) % );
update(mid);
return mid;
}
bool CheckInclude(int k) {
if(T[k].mn[] >= Ql && T[k].mx[] <= Qr
&& T[k].mx[] < Ql && T[k].mn[] > Qr) return ;
return ;
}
bool CheckCross(int k) {
if(T[k].tp.x[] >= Ql && T[k].tp.x[] <= Qr
&& T[k].tp.x[] < Ql && T[k].tp.x[] > Qr) return ;
return ;
}
bool CheckNotCross(int k) {
if(T[k].mn[] >= Ql || T[k].mx[] <= Qr || T[k].mx[] < Ql || T[k].mn[] > Qr) return ;
return ;
}
void Query(int k) {
if(CheckInclude(k)) {
lastans = max(lastans, T[k].val); return ; //矩形完全包含在查询区间内
}
if(CheckCross(k))
lastans = max(lastans, T[k].tp.x[]); //相交
if(CheckNotCross(k)) return ; // 没有重合的地方
int disl = T[ls(k)].val, disr = T[rs(k)].val;
if(disl > disr) {
if(disl > lastans) Query(ls(k));
if(disr > lastans) Query(rs(k));
}
else {
if(disr > lastans) Query(rs(k));
if(disl > lastans) Query(ls(k));
}
}
int main() {
#ifdef WIN32
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
N = read(); M = read();
for(int i = ; i <= N; i++) a[i] = read();
for(int i = ; i <= N; i++) pre[i] = happen[a[i]], happen[a[i]] = i;
for(int i = ; i <= N; i++) happen[a[i]] = N + ;
for(int i = N; i >= ; i--) nxt[i] = happen[a[i]], happen[a[i]] = i;
for(int i = ; i <= N; i++)
P[i] = (Point) {i, pre[i], nxt[i], a[i]};
root = Build(, N, );
for(int i = ; i <= M; i++) {
int x = read(), y = read();
Ql = min((x + lastans) % N + ,(y + lastans) % N + );
Qr = max((x + lastans) % N + ,(y + lastans) % N + );
lastans = ;
Query(root);
printf("%d\n", lastans);
}
return ;
}
 
 

BZOJ 3489: A simple rmq problem(K-D Tree)的更多相关文章

  1. BZOJ 3489: A simple rmq problem

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

  2. 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][ ...

  3. [BZOJ 3489] A simple rmq problem 【可持久化树套树】

    题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有 ...

  4. bzoj 3489 A simple rmq problem - 线段树

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

  5. BZOJ 3489 A simple rmq problem 可持久化KDtree/二维线段树

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题意概述: 给出一个序列,每次询问一个序列区间中仅出现了一次的数字最大是多少,如果 ...

  6. bzoj 3489 A simple rmq problem——主席树套线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9b ...

  7. BZOJ 3489 A simple rmq problem(可持久化线段树)

    题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3489 题意:一个数列.每次询问一个区间内出现一次的最大的数字是多少. 思路:设la ...

  8. bzoj 3489 A simple rmq problem —— 主席树套线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9b ...

  9. BZOJ 3489 A simple rmq problem ——KD-Tree

    考前写写板子. 用$(i,pre[i],nxt[i])$来描述一个点,然后就变成了区间求最值的问题. KD-Tree 由低维转向高维的方法,可以用来敲暴力. 剩下就是KD-Tree的基本操作了. #i ...

随机推荐

  1. 微服务架构之spring cloud ribbon

    现在负载均衡是通用的解决分压的技术方案,实现方式一般分为服务端或者客户端,服务端大部分是使用中间件实现,spring cloud ribbon 是一个客户端负载均衡组件.跟spring cloud e ...

  2. 线性表接口的实现_Java

    线性表是其组成元素间具有线性关系的一种线性结构,对线性表的基本操作主要有插入.删除.查找.替换等,这些操作可以在线性表的任何位置进行.线性表可以采用顺序存储结构和链式存储结构表示. 本接口的类属于da ...

  3. ViewDragHelper详解(侧滑栏)

    1.Drag拖拽:ViewDrag拖拽视图,拖拽控件:ViewDragHelper拖拽视图助手,拖拽操作类.利用ViewDragHelper类可以实现很多绚丽的效果,比如:拖拽删除,拖拽排序,侧滑栏等 ...

  4. ubuntu16.0.4安装mysql5.7以及设置远程访问

    1.安装mysql命令 sudo apt-get install mysql-server sudo apt install mysql-client sudo apt install libmysq ...

  5. [转]Apache的CRT格式SSL证书转换成IIS用的PFX格式

    转自:http://www.getvm.net/apache-crt-ssl-convert-to-iis-pfx/ Apache使用的SSL证书是.crt格式,如果你的网站从Apache换到了win ...

  6. 数据预处理(Python scikit-learn)

    在机器学习任务中,经常会对数据进行预处理.如尺度变换,标准化,二值化,正规化.至于采用哪种方法更有效,则与数据分布和采用算法有关.不同算法对数据的假设不同,可能需要不同的变换,而且有时无需进行变换,也 ...

  7. 将csv导出json格式

    将csv导出json格式 import os,csv,json cf = open('D:\OneDrive\\Tech\\Script\\Powershell_Script\\Uxin_work\\ ...

  8. Linux基础和常用命令

    经常使用的命令: #查看端口被占用情况 netstat -tunlp|grep #查看java进程 ps -ef|grep java #压缩前端工程 rar a -ep1 ./update/win32 ...

  9. 乘风破浪:LeetCode真题_011_Container With Most Water

    乘风破浪:LeetCode真题_011_Container With Most Water 一.前言 下面我们继续进行编程练习,可以说对于实际问题的活学活用是非常重要的.比如我们这次的题目,就需要从中 ...

  10. mysql DML语句学习1

    DML 操作是指对数据库中表记录的操作,主要包括表记录插入(insert).更新(update).删除(delete)和查询(select) 1. 插入记录 表创建好后,就可以往里插入记录,基本语句如 ...