P4425 [HNOI/AHOI2018]转盘
这次算是对楼房重建问题有一个初步理解了。大体就是先处理一个区间对另一个区间的影响,再处理另一个区间的影响。对于这个题:
就是维护一个后缀单调栈。复杂度 \(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\n", 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\n", 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);
}