P4425 [HNOI/AHOI2018]转盘

P4425 [HNOI/AHOI2018]转盘

这次算是对楼房重建问题有一个初步理解了。大体就是先处理一个区间对另一个区间的影响,再处理另一个区间的影响。对于这个题:

\[\displaystyle \begin{array}{l} \textbf{def:} \ \text{ask} (node, val) \\ \qquad \textbf{if} \ (node \ \text{is leafy node}) \\ \qquad \qquad \textbf{return} \ [t[node].maxn > val] * inf + val + t[node].l \\ \qquad \textbf{else} \\ \qquad \qquad \textbf{if} \ (t[node << 1 | 1].maxn > val) \\ \qquad \qquad \qquad \textbf{return} \ \min(\text{ask}(node << 1 | 1, val), t[node].tr) \\ \qquad \qquad \textbf{else} \\ \qquad \qquad \qquad \textbf{return} \ \text{ask}(node << 1, val) \\ \qquad \qquad \textbf{endif.} \\ \qquad \textbf{endif.} \\ \textbf{enddef.} \end{array} \]

就是维护一个后缀单调栈。复杂度 \(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);
}
posted @ 2021-01-16 09:05  Gensokyo_Alice  阅读(128)  评论(0编辑  收藏  举报