这次算是对楼房重建问题有一个初步理解了。大体就是先处理一个区间对另一个区间的影响,再处理另一个区间的影响。对于这个题:
就是维护一个后缀单调栈。复杂度 (O(n log^2n))
下面是这个题的推式子。
可以发现,这个题就是先在某个地方停一会,然后不停下脚步走一圈。先断开环转化为 (2N)。
那么考虑对于一个地方 (i) 其出现时间为 (t_i)。假定从 (j) 出发,在 (j) 停下时间至少为 (t_i - (i - j)) 那么答案就是 (displaystyle min_{j=1}^N{ max_{i=j}^{j+N-1}{ t_i - i } + j} + N - 1) 。(N-1) 是走完这一圈。
考虑 (t_i = t_{i+N}) 且 (i lt i+N) 所以 (t_i - i gt t_{i+N} - (i+N)) 。那么转化为 (displaystyle min_{j=1}^N{ max_{i=j}^{2N}{ t_i - i } + j} + N - 1)。
可以发现,对于 (t_i - i) 固定,直到前面一个大于它的 (t_j - j),答案永远由他决定,且答案为 (t_i - i + j + 1)。所以我们可以考虑单调栈维护 (t_i - i)。
假定单调栈元素为 (st_i),设 (st_0 = 0),(st_{bound-1} lt N le st_{bound})。
(displaystyle ans = min_{i=1}^{bound}(t_{st_i}- st_i + st_{i-1}) + N) 这题就维护一下 (t_i-i) 的单调栈就好了。
因为 (i lt bound) 时 (st_{i} gt N) 所以,这些最大值就是 ([1, N]) 里的最大值 (-N)。所以只需要维护 ([1, N])。最后在 ([1, N]) 上二分到位置之后加上长度就完了。
/*
Name:
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <ctime>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
const ll MAXN = (1LL << 20) + 10, INF = 0x3f3f3f3f3f3f3f3f;
ll N, M, P, lst, val[MAXN];
struct nod {
ll l, r, maxn, tr;
nod (ll _l = 0, ll _r = 0, ll _maxn = 0, ll _tr = 0): l(_l), r(_r), maxn(_maxn), tr(_tr) {};
} t[MAXN];
void build(ll, ll, ll);
void ins(ll, ll, ll);
ll ask(ll, ll);
void pushup(ll);
int main() {
scanf("%lld%lld%lld", &N, &M, &P);
for (ll i = 1; i <= N; i++) scanf("%lld", val+i);
build(1, 1, N); printf("%lld
", lst = ask(1, t[1].maxn - N) + N);
for (ll i = 1, x, y; i <= M; i++) {
scanf("%lld%lld", &x, &y);
if (P) x ^= lst, y ^= lst;
val[x] = y; ins(1, x, y);
printf("%lld
", lst = ask(1, t[1].maxn - N) + N);
}
return 0;
}
void build(ll node, ll l, ll r) {
t[node] = nod(l, r);
if (l == r) {t[node].maxn = (val[l] - l); return;}
ll mid = (l + r) >> 1;
build(node << 1, l, mid);
build(node << 1 | 1, mid + 1, r);
pushup(node);
}
void pushup(ll node) {
t[node].maxn = max(t[node << 1].maxn, t[node << 1 | 1].maxn);
t[node].tr = ask(node << 1, t[node << 1 | 1].maxn);
}
ll ask(ll node, ll pos) {
if (t[node].l == t[node].r) return t[node].maxn > pos ? pos + t[node].l : INF;
if (t[node << 1 | 1].maxn > pos) return min(t[node].tr, ask(node << 1 | 1, pos));
else return ask(node << 1, pos);
}
void ins(ll node, ll pos, ll v) {
if (t[node].l == pos && t[node].r == pos) {t[node].maxn = v - pos; return;}
ll mid = (t[node].l + t[node].r) >> 1;
if (pos <= mid) ins(node << 1, pos, v);
else ins(node << 1 | 1, pos, v);
pushup(node);
}