您的位置:首页 > 其它

BZOJ 3489 A simple rmq problem

2015-01-29 22:08 375 查看

3489: A simple rmq problem

Time Limit: 10 Sec Memory Limit: 512 MB

Submit: 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 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

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: