Logu P4425 [HNOI/AHOI2018] turntable (line segment tree)

Keywords: C++

meaning of the title

Title Link

Sol

First of all, guess a conclusion: for each query, it must be optimal to enumerate a starting point and wait until a certain point appears before going to the next point.

It can't be proved. I took 3w group in the examination room. That's right...

First, it is convenient to enumerate the starting point by doubling the array length, and then it is a monotonous queue model. Sort it out. That's what we need

\[n - 1 + \min_{i=1}^n i + (\max_{j=i}^{2n} t[j] - j)\]

(\ (t[j] \) indicates the time when the \ (j \) position appears. I n fact, the upper bound of \ (\ max \) should be \ (i + n - 1 \), but obviously the later parts will not be better.)

Among them \ (n-1 \) and \ (t[j] - j \) can be calculated directly, which can be maintained by line tree.

For each interval maintenance \ (mx[i] \) represents the maximum value of the interval, \ (ans[i] \) represents the \ (min(i + \max\text {suffix}) \) of the left interval under the influence of the right interval

When merging, the influence of right interval on left interval is considered.

If \ (MX [RS] < MX [LS] \), we can directly update the answer with \ (ans[ls] \), and then recurse \ (ls(rs) \)

Otherwise, update the answer with mid and recurse \ (ls(ls) \)

In this way, half of the interval can be eliminated each time, so the complexity is \ (O(nlog^2n) \)

At the end of the query, the maximum value of \ ([n + 1, 2n] \) can be directly divided into two parts. In fact, the value of this part is \ (max[1, n] - n \)

Then you only need to maintain the segment tree of \ ([1, n] \)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e6 + 10, INF = 1e9 + 7;
template<typename A, typename B> inline bool chmin(A &x, B y) {
    if(x > y) {x = y; return 1;}
    else return 0;
}
template<typename A, typename B> inline bool chmax(A &x, B y) {
    if(x < y) {x = y; return 1;}
    return 0;
}
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, P, t[MAXN],  q[MAXN];
int ans[MAXN], mx[MAXN];
#define ls k << 1
#define rs k << 1 | 1
int Query(int k, int l, int r, int val) {
    if(l == r) return l + max(mx[k], val);
    int mid = l + r >> 1;
    if(val < mx[rs]) return min(ans[k], Query(rs, mid + 1, r, val));
    else return min(mid + val + 1, Query(ls, l, mid, val)); 
}
void update(int k, int l, int r) {
    mx[k] = max(mx[ls], mx[rs]);
    ans[k] = Query(ls, l, (l + r) >> 1, mx[rs]);
}
void Modify(int k, int l, int r, int p, int v) {
    if(l == r) {mx[k] = v; return ;}
    int mid = l + r >> 1;
    if(p <= mid) Modify(ls, l, mid, p, v);
    else Modify(rs, mid + 1, r, p, v);
    update(k, l, r);
}
void Build(int k, int l, int r) {
    if(l == r) {mx[k] = t[l]; return ;}
    int mid = l + r >> 1;
    Build(ls, l, mid); Build(rs, mid + 1, r);
    update(k, l, r);
}
int main() {
    N = read(); M = read(); P = read();
    for(int i = 1; i <= N; i++) t[i] = read();
    for(int i = 1; i <= N; i++) t[i] -= i;
    Build(1, 1, N); int las = 0;
    printf("%d\n", las = (Query(1, 1, N, mx[1] - N) + N - 1));
    while(M--) {
        int x = read(), y = read();
        if(P) x ^= las, y ^= las;
        Modify(1, 1, N, x, y - x);
        printf("%d\n", las = (Query(1, 1, N, mx[1] - N) + N - 1));
    }
    return 0;
}
/*
5 0 0
1 2 5 4 0
*/

Posted by ziggs on Sat, 30 Nov 2019 03:57:54 -0800