BZOJ 3489 A simple rmq problem
2015-01-29 22:08
375 查看
3489: A simple rmq problem
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 326 Solved: 85
[Submit][Status]
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 106 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
410
10
0
0
10
0
4
0
4
Solution
这个题我们可以:“矩阵主席树”。=_= shen me gui =_= shen me gui =_= shen me gui =_= shen me gui =_=
我们考虑对于序列中的一个元素 x:
设它的前驱为 a,若没有前驱则视为 0,
设它的后继为 b,若没有后继则视为 n + 1。
然后对于左端点在 [a + 1, x],右端点在 [x, b - 1] 中的区间,
都会只包含这个元素 1 次。
于是我们考虑设置一个矩阵。
第一维是左端点,第二维是右端点,
矩阵中的每个元素就代表一个区间。
于是我们考虑给每一个值维护一个矩阵。
然而,真的有必要吗?
我们可以记录一个“后缀矩阵”。
即矩阵 i 就代表着把 [i, n] 中的所有矩阵给合并起来,
也就是有 Suffix_Matrix[i][j][k] = or_sum(Matrix[t][j][k]) (t = i to n)。
然后这个东西可以用主席树来维护嘛。
然后询问的时候就二分答案单点查询就可以了。
由于单次矩阵赋值操作的复杂度是 O(log^2 n) 的。
并且每个元素只会对操作次数产生 1 的贡献。
所以操作部分的复杂度是 O(n log^2 n) 的。
单点查询的复杂度是 O(log n) 的,
然后对于每个询问我们要二分答案,
于是单次处理询问的复杂度也是 O(log^2 n) 的。
于是回答询问的复杂度是 O(m log^2 n) 的。
所以总时间复杂度就是 O((n + m) log^2 n) 的。
然后我们可以把标记永久化,即不下传,
反正值只会是 0 或者 1,并且只可能从 0 变 1 而不会从 1 变 0。
所以你整个矩阵都是 1 了单点还难道不是 1 吗?
所以就没必要下传标记了。
这可以大大节省空间。
然后这样优化之后才能过掉这个题。。。
于是我亲切地把这货叫做“矩阵主席树”=_=
毕竟 Gromah 太弱,只会做水题。
Gromah's Code
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define N 300000 + 5 #define M 42000000 + 5 int n, m, tot, cnt, Head , Root ; struct Chain { int next, node; }E ; struct Node { int l, r; bool d, flag; }h[M]; inline int getint() { char ch = '\n'; for (; ch > '9' || ch < '0'; ch = getchar()) ; int res = ch - '0'; for (ch = getchar(); ch >= '0' && ch <= '9'; ch = getchar()) res = (res << 3) + (res << 1) + ch - '0'; return res; } inline void addedge(int u, int v) { E[++ tot].next = Head[u]; Head[u] = tot; E[tot].node = v; } inline int Inc(int a, int b) { return a + b - (a + b >= n ? n : 0) + 1; } inline void update(int x) { h[x].flag = h[h[x].l].flag | h[h[x].r].flag; } inline void apply(int x) { h[x].d = h[x].flag = 1; } inline void Modify(int &x, int t, int b, int l, int r, int st, int sb, int sl, int sr) { h[++ cnt] = h[x]; x = cnt; if (t == st && b == sb && l == sl && r == sr) { apply(x); return ; } if (h[x].d) return ; if (b - t >= r - l) { int mid = t + b >> 1; if (sb <= mid) Modify(h[x].l, t, mid, l, r, st, sb, sl, sr); else if (st > mid) Modify(h[x].r, mid + 1, b, l, r, st, sb, sl, sr); else Modify(h[x].l, t, mid, l, r, st, mid, sl, sr), Modify(h[x].r, mid + 1, b, l, r, mid + 1, sb, sl, sr); } else if (b - t < r - l) { int mid = l + r >> 1; if (sr <= mid) Modify(h[x].l, t, b, l, mid, st, sb, sl, sr); else if (sl > mid) Modify(h[x].r, t, b, mid + 1, r, st, sb, sl, sr); else Modify(h[x].l, t, b, l, mid, st, sb, sl, mid), Modify(h[x].r, t, b, mid + 1, r, st, sb, mid + 1, sr); } update(x); } inline bool Query(int x, int t, int b, int l, int r, int u, int v) { if (!h[x].flag) return 0; if (h[x].d) return 1; if (t == b && l == r) return h[x].flag; if (b - t >= r - l) { int mid = t + b >> 1; if (u <= mid) return Query(h[x].l, t, mid, l, r, u, v); else return Query(h[x].r, mid + 1, b, l, r, u, v); } else if (b - t < r - l) { int mid = l + r >> 1; if (v <= mid) return Query(h[x].l, t, b, l, mid, u, v); else return Query(h[x].r, t, b, mid + 1, r, u, v); } } int main() { n = getint(), m = getint(); for (int i = 1; i <= n; i ++) addedge(i, 0); for (int i = 1; i <= n; i ++) addedge(getint(), i); for (int i = 1; i <= n; i ++) addedge(i, n + 1); for (int i = n; i; i --) { int a, b, c; a = E[Head[i]].node; b = E[Head[i] = E[Head[i]].next].node; Root[i] = Root[i + 1]; while (E[Head[i]].next) { Head[i] = E[Head[i]].next; int c = E[Head[i]].node; Modify(Root[i], 1, n, 1, n, c + 1, b, b, a - 1); a = b, b = c; } } int last = 0; while (m --) { int x = Inc(getint(), last), y = Inc(getint(), last), l = 0, r = n; if (x > y) swap(x, y); while (l < r) { int mid = l + r + 1 >> 1; if (Query(Root[mid], 1, n, 1, n, x, y)) l = mid; else r = mid - 1; } printf("%d\n", last = l); } return 0; }
相关文章推荐
- 【kd-tree】bzoj3489 A simple rmq problem
- bzoj 3489: A simple rmq problem k-d树思想大暴力
- BZOJ3489 A simple rmq problem
- bzoj 3489 - A simple rmq problem
- BZOJ 3489 A simple rmq problem(可持久化线段树)
- bzoj3489 A simple rmq problem
- 【BZOJ3489】A simple rmq problem kd-tree
- [BZOJ 3489]A simple rmq problem
- [bzoj3489]A simple rmq problem
- bzoj3489 A simple rmq problem
- [bzoj3489] A simple rmq problem 解题报告
- [BZOJ]3489 A simple rmq problem 主席树套树
- 【BZOJ3489】A simple rmq problem
- BZOJ 3489: A simple rmq problem 树套树
- BZOJ 3489 A simple rmq problem ——KD-Tree
- bzoj 3489: A simple rmq problem
- bzoj 3489: A simple rmq problem 可持久化线段树套可持久化线段树
- BZOJ3489 A simple rmq problem
- bzoj 3489: A simple rmq problem (KD-tree)
- BZOJ 3489 A simple rmq problem