BZOJ 3489: A simple rmq problem
3489: A simple rmq problem
Time Limit: 40 Sec Memory Limit: 600 MB
Submit: 1594 Solved: 520
[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
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
10
10
0
0
10
0
4
0
4
HINT
注意出题人为了方便,input的第二行最后多了个空格。
2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测
Source
参考了网上的一些做法,可持久化树套树什么的实在吃不消,于是采用了KD-Tree的方法。
考虑一个点,在哪个区间内它是唯一出现的呢?
设prev[i]为上一个和i处权值相同的位置,next[i]为下一个和i处权值相同的位置,显然在(prev[i],next[i])这个区间内,i点是该权值唯一出现的位置。
对于一个询问(ql,qr),我们可以转换为:找出满足 prev[i] < ql 且 next[i] > qr 且 ql <= i <= qr 的i中,权值最大的i。这个就是KD-Tree维护三维的区间最值问题。
#include <bits/stdc++.h> inline int getC(void) {
static const int siz = ; static char buf[siz];
static char *hd = buf + siz;
static char *tl = buf + siz; if (hd == tl)
fread(hd = buf, , siz, stdin); return int(*hd++);
} inline int getI(void) {
register int ret = ;
register int neg = false;
register int bit = getC(); for (; bit < ; bit = getC())
if (bit == '-')neg ^= true; for (; bit > ; bit = getC())
ret = ret * + bit - ''; return neg ? -ret : ret;
} template <class T>
inline T min(const T &a, const T &b) {
return a < b ? a : b;
} template <class T>
inline T max(const T &a, const T &b) {
return a > b ? a : b;
} const int maxn = ; int n, m;
int answer;
int num[maxn]; int next[maxn];
int prev[maxn];
int last[maxn]; int value[maxn][]; int pos[maxn];
int maxv[maxn];
int lson[maxn];
int rson[maxn];
int mini[maxn][];
int maxi[maxn][]; int qryL, qryR; int cmpK; inline bool cmp(const int &a, const int &b) {
return value[a][cmpK] < value[b][cmpK];
} int build(int l, int r, int k) {
int mid = (l + r) >> ; cmpK = k;
std::nth_element(
pos + l, pos + mid, pos + r + , cmp);
maxv[mid] = num[pos[mid]];
for (int i = ; i < ; ++i)
mini[mid][i] = maxi[mid][i] = value[pos[mid]][i];
if (l < mid) {
lson[mid] = build(l, mid - , (k + ) % );
maxv[mid] = max(maxv[mid], maxv[lson[mid]]);
for (int i = ; i < ; ++i) {
mini[mid][i] = min(mini[mid][i], mini[lson[mid]][i]);
maxi[mid][i] = max(maxi[mid][i], maxi[lson[mid]][i]);
}
}
if (r > mid) {
rson[mid] = build(mid + , r, (k + ) % );
maxv[mid] = max(maxv[mid], maxv[rson[mid]]);
for (int i = ; i < ; ++i) {
mini[mid][i] = min(mini[mid][i], mini[rson[mid]][i]);
maxi[mid][i] = max(maxi[mid][i], maxi[rson[mid]][i]);
}
}
return mid;
} inline bool check(int t) {
if (mini[t][] > qryR || maxi[t][] < qryL)return false;
if (mini[t][] >= qryL || maxi[t][] <= qryR)return false;
return true;
} void query(int t) {
if (mini[t][] >= qryL && maxi[t][] <= qryR && maxi[t][] < qryL && mini[t][] > qryR)
{ answer = max(answer, maxv[t]); return; }
if (pos[t] >= qryL && pos[t] <= qryR && prev[pos[t]] < qryL && next[pos[t]] > qryR)
answer = max(answer, num[pos[t]]);
if (maxv[lson[t]] > maxv[rson[t]]) {
if (lson[t] && maxv[lson[t]] > answer && check(lson[t]))query(lson[t]);
if (rson[t] && maxv[rson[t]] > answer && check(rson[t]))query(rson[t]);
}
else {
if (rson[t] && maxv[rson[t]] > answer && check(rson[t]))query(rson[t]);
if (lson[t] && maxv[lson[t]] > answer && check(lson[t]))query(lson[t]);
}
} signed main(void) {
n = getI();
m = getI(); for (int i = ; i <= n; ++i)
num[i] = getI(); for (int i = ; i <= n; ++i)
last[i] = ; for (int i = ; i <= n; ++i)
prev[i] = last[num[i]], last[num[i]] = i; for (int i = n; i >= ; --i)
last[i] = n + ; for (int i = n; i >= ; --i)
next[i] = last[num[i]], last[num[i]] = i; for (int i = ; i <= n; ++i) {
pos[i] = i;
value[i][] = i;
value[i][] = prev[i];
value[i][] = next[i];
} int root = build(, n, ); for (int i = ; i <= m; ++i) {
int x = getI();
int y = getI();
qryL = (x + answer) % n + ;
qryR = (y + answer) % n + ;
if (qryL > qryR)
qryL ^= (qryR ^= (qryL ^= qryR));
answer = ; query(root); printf("%d\n", answer);
}
}
@Author: YouSiki
BZOJ 3489: A simple rmq problem的更多相关文章
- 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][ ...
- [BZOJ 3489] A simple rmq problem 【可持久化树套树】
题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有 ...
- bzoj 3489 A simple rmq problem - 线段树
Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直 ...
- BZOJ 3489 A simple rmq problem(可持久化线段树)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3489 题意:一个数列.每次询问一个区间内出现一次的最大的数字是多少. 思路:设la ...
- BZOJ 3489 A simple rmq problem 可持久化KDtree/二维线段树
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题意概述: 给出一个序列,每次询问一个序列区间中仅出现了一次的数字最大是多少,如果 ...
- bzoj 3489 A simple rmq problem——主席树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9b ...
- bzoj 3489 A simple rmq problem —— 主席树套线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9b ...
- BZOJ.3489.A simple rmq problem(主席树 Heap)
题目链接 当时没用markdown写,可能看起来比较难受...可以复制到别的地方看比如DevC++. \(Description\) 给定一个长为n的序列,多次询问[l,r]中最大的只出现一次的数.强 ...
- BZOJ 3489: A simple rmq problem(K-D Tree)
Time Limit: 40 Sec Memory Limit: 512 MBSubmit: 2579 Solved: 888[Submit][Status][Discuss] Descripti ...
随机推荐
- 【重大更新】开源跨平台物联网通讯框架ServerSuperIO 2.0(SSIO)下载
更新具体细节参见:[更新设计]跨平台物联网通讯框架ServerSuperIO 2.0 ,功能.BUG.细节说明,以及升级思考过程! 声明:公司在建设工业大数据平台,SSIO正好能派上用场,所以抓紧时间 ...
- LinqToXml (一) Create Xml file By Dom /Linq
目前,在xml 应用编程领域比较流行的开发模型是W3C 提供的DOM(文档对象模型),在.net Framework 通过命名空间 System.Xml 对该技术提供了支持.随着Linq to XMl ...
- 如何解决MSI类型的Sharepoint Server2016 安装即点即用的office 2016 plus问题
前提 在sharepoint server 2016安装office 2016 plus提示如下错误: 解决方法 Ø 概念 1. 即点和即用的概念:即点即用是一种通过 Internet 安装和更新 O ...
- SharePoint 2013 开发教程
做了SharePoint有三年了,大家经常会问到,你的SharePoint是怎么学的,想想自己的水平,也不过是初级开发罢了.因为,SharePoint开发需要接触的东西太多了,Windows操作系统. ...
- iOS 获取设备唯一标示符的方法
在开发中会遇到应用需要记录设备标示,即使应用卸载后再安装也可重新识别的情况,在这写一种实现方式--读取设备的UUID(Universally Unique Identifier)并通过KeyChain ...
- AC算法学习笔记
1.算法流程图 (1) void Init() 此函数是初始化函数,用来给fail数组和goto数组初始化值. (2) void GotoFunction(string x) 这个函数的作 ...
- ubuntu 16.04 安装nodejs
经过几天的尝试,终于装好了: 1. nodejs官方推荐一下安装方式: NodeSource的二进制安装脚本NodeSource Using Ubuntu curl -sL https://deb.n ...
- Drop all the tables, stored procedures, triggers, constraints and all the dependencies in one SQL statement
Is there any way in which I can clean a database in SQl Server 2005 by dropping all the tables and d ...
- 企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET
先看效果 1.本文演示的是微信[企业号]的H5页面微信支付 2.本项目基于开源微信框架WeiXinMPSDK开发:https://github.com/JeffreySu/WeiXinMPSDK 感谢 ...
- Java 数组
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同. Java语言中提供的数组是用来存储固定大小的同类型元素. 你可以声明一个数组变量,如numbers[100 ...