洛谷P4425 [HNOI/AHOI2018]轉盤(線段樹)

自為風月馬前卒發表於2019-02-22

題意

題目連結

Sol

首先猜一個結論:對於每次詢問,列舉一個起點然後不斷等到某個點出現時才走到下一個點一定是最優的。

證明不會,考場上拍了3w組沒錯應該就是對的吧。。。

首先把陣列倍長一下方便列舉起點,然後就是一個單調佇列的模型了。整理一下我們需要求的東西就是這個

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

((t[j])表示第(j)個位置出現的時間,其實(max)的上界應該是(i + n – 1)的,但是顯然後面的部分都不會更優)

其中(n-1)(t[j] – j)可以直接算,這玩意兒可以用線段樹維護。

對於每個區間維護(mx[i])表示區間最大值,(ans[i])表示在右區間的影響下,左區間的(min(i + max ext{字尾}))

合併時考慮右區間對左區間的影響。

如果(mx[rs] < mx[ls]),我們可以直接用(ans[ls])更新答案,然後遞迴(ls(rs))

否則用mid更新一下答案然後遞迴(ls(ls))

這樣每次可以消除掉一半的區間,因此複雜度是(O(nlog^2n))

最後詢問的時候可以直接拿([n + 1, 2n])的最大值去二分,實際上這部分的值就是(max[1, n] – n)

那麼只需要維護([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
", 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
", las = (Query(1, 1, N, mx[1] - N) + N - 1));
    }
    return 0;
}
/*
5 0 0
1 2 5 4 0
*/

相關文章