标签:
[BZOJ3489]A simple rmq problem
试题描述
输入
第一行为两个整数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的第二行最后多了个空格。
输出
输入示例
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; }
[BZOJ3489]A simple rmq problem
标签:
原文地址:http://www.cnblogs.com/xiao-ju-ruo-xjr/p/5688879.html