[BZOJ3489]A simple rmq problem
[BZOJ3489]A simple rmq problem
试题描述
因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。
输入
第一行为两个整数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
注意出题人为了方便,input的第二行最后多了个空格。
输出
一共M行,每行给出每个询问的答案。
输入示例
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
输出示例
4 10 10 0 0 10 0 4 0 4
数据规模及约定
见“输入”
题解
预处理一下,对于每一个数,将离它最近的与它相等的数的位置求出来,左边的位置表示成 pre[i],右边的位置表示成 nxt[i],如果没有左边的相同的数字则 pre[i] = 0,若没有右边的相同的数字则 nxt[i] = n + 1. 那么第 i 个数在空间中可以表示成 (i, pre[i], nxt[i]) 这个点,当一个询问 [L, R] 到来时,就是查询所有满足 L <= i <= R & pre[i] < L & R < nxt[i] 的最大点权。不难发现这是一个空间中的长方体,可以用树套树套树解决。
当然只有区间查询的 kd 树还是有复杂度保证的。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
#include <ctime>
using namespace std;
const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
if(Head == Tail) {
int l = fread(buffer, 1, BufferSize, stdin);
Tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
}
#define maxn 100010
#define oo 2147483647
int n, m, root, lc[maxn], rc[maxn], Cur, A[maxn], now[maxn];
struct Node {
int x[3], mx[3], mn[3], val, maxv;
bool operator < (const Node& t) const { return x[Cur] < t.x[Cur]; }
} ns[maxn];
void maintain(int o) {
int l = lc[o], r = rc[o];
for(int i = 0; i < 3; i++) {
ns[o].mx[i] = max(max(ns[l].mx[i], ns[r].mx[i]), ns[o].x[i]);
ns[o].mn[i] = min(min(ns[l].mn[i], ns[r].mn[i]), ns[o].x[i]);
}
ns[o].maxv = max(max(ns[l].maxv, ns[r].maxv), ns[o].val);
return ;
}
void build(int& o, int L, int R, int cur) {
if(L > R){ o = 0; return ; }
int M = L + R >> 1; o = M;
Cur = cur; nth_element(ns + L, ns + M, ns + R + 1);
build(lc[o], L, M - 1, (cur + 1) % 3); build(rc[o], M + 1, R, (cur + 1) % 3);
maintain(o);
return ;
}
int ql, qr;
bool all(int o) { return ql <= ns[o].mn[0] && ns[o].mx[0] <= qr && ns[o].mx[1] < ql && ns[o].mn[2] > qr; }
bool has(int o) { return ql <= ns[o].mx[0] && ns[o].mn[0] <= qr && ns[o].mn[1] < ql && ns[o].mx[2] > qr; }
int query(int o) {
if(!o) return 0;
int ans = 0, l = lc[o], r = rc[o];
if(ns[l].maxv > ns[r].maxv) {
if(ns[l].maxv > ans) {
if(all(l)) ans = max(ans, ns[l].maxv);
else if(has(l)) ans = max(ans, query(l));
}
if(ns[r].maxv > ans) {
if(all(r)) ans = max(ans, ns[r].maxv);
else if(has(r)) ans = max(ans, query(r));
}
}
else {
if(ns[r].maxv > ans) {
if(all(r)) ans = max(ans, ns[r].maxv);
else if(has(r)) ans = max(ans, query(r));
}
if(ns[l].maxv > ans) {
if(all(l)) ans = max(ans, ns[l].maxv);
else if(has(l)) ans = max(ans, query(l));
}
}
int x = ns[o].x[0], pre = ns[o].x[1], nxt = ns[o].x[2];
if(ql <= x && x <= qr && pre < ql && nxt > qr) ans = max(ans, ns[o].val);
return ans;
}
int main() {
// freopen("data.in", "r", stdin);
// freopen("data.out", "w", stdout);
// int clo = clock();
ns[0].mx[0] = ns[0].mx[1] = ns[0].mx[2] = -oo;
ns[0].mn[0] = ns[0].mn[1] = ns[0].mn[2] = oo;
ns[0].maxv = -oo;
n = read(); m = read();
for(int i = 1; i <= n; i++) {
A[i] = read();
ns[i].x[0] = i; ns[i].x[1] = now[A[i]];
now[A[i]] = i;
}
for(int i = 1; i <= n; i++) now[i] = n+1;
for(int i = n; i; i--) {
ns[i].x[2] = now[A[i]]; ns[i].maxv = ns[i].val = A[i];
now[A[i]] = i;
}
build(root, 1, n, 0);
int lastans = 0;
while(m--) {
int x = read(), y = read();
ql = min((x + lastans) % n + 1, (y + lastans) % n + 1);
qr = max((x + lastans) % n + 1, (y + lastans) % n + 1);
lastans = query(root);
printf("%d\n", lastans);
}
// printf("%d\n", clock() - clo);
return 0;
}

浙公网安备 33010602011771号