Chattering

L(i, j)表示从 i 开始 2 ^ j 秒之后能到达的最左端

R(i, j)表示从 i 开始 2 ^ j 秒之后能到达的最右端

那么L(i, j) = min(L(t, j - 1))  L(i, j - 1) <= t <= R(i, j - 1)

       R(i, j) = max(R(t, j - 1))    L(i, j - 1) <= t <= R(i, j - 1)

求出这个之后就倍增一下求答案就好了。 这样是个n(logn) ^ 2的方法。

其实再进一步我们可以发现每次转移其实只会从min(L(t, 0)) 和 max(R(t, 0)) L(i, j - 1) <= t <= R(i, j - 1) 

这两个地方转移过来, 所以就能优化成一个log

#include<bits/stdc++.h>
using namespace std;

const int N = (int)3e5 + 7;
const int LOG = 19;

int n, a[N], b[N], c[N];
int Log[N];
int l[LOG][N], r[LOG][N];

struct Rmq {
    int a[N][LOG], val[N]; int type;
    inline int Max(int x, int y) {
        return (val[x] < val[y]) ? y : x;
    }
    void build(int *b, int n, int _type) {
        type = _type;
        for(int i = 1; i <= n; i++) a[i][0] = i, val[i] = type * b[i];
        for(int j = 1; j <= Log[n]; j++) {
            for(int i = 1; i + (1 << j) - 1 <= n; i++) {
                a[i][j] = Max(a[i][j - 1], a[i + (1 << j - 1)][j - 1]);
            }
        }
    }
    inline int query(int l, int r) {
        int k = Log[r - l + 1];
        return Max(a[l][k], a[r - (1 << k) + 1][k]);
    }
} rmq_l, rmq_r;

int main() {
    scanf("%d", &n);
    for(int i = 2; i <= 3 * n; i++) Log[i] = Log[i >> 1] + 1;
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        a[i + n] = a[i + n * 2] = a[i];
    }
    if(n == 1) return puts("0 "), 0;
    for(int i = 1; i <= 3 * n; i++) {
        b[i] = max(1, i - a[i]);
        c[i] = min(3 * n, i + a[i]);
    }
    for(int i = 0; i <= Log[3 * n]; i++) r[i][3 * n] = 3 * n;
    for(int i = 0; i <= Log[3 * n]; i++) l[i][1] = 1;
    for(int i = 1; i <= 3 * n; i++) {
        l[0][i] = b[i];
        r[0][i] = c[i];
    }
    rmq_l.build(l[0], n * 3, -1);
    rmq_r.build(r[0], n * 3, 1);
    for(int i = 1; i <= Log[3 * n]; i++) {
        for(int j = 1; j <= 3 * n; j++) {
            int posl = rmq_l.query(l[i - 1][j], r[i - 1][j]);
            int posr = rmq_r.query(l[i - 1][j], r[i - 1][j]);
            l[i][j] = min(l[i - 1][posl], l[i - 1][posr]);
            r[i][j] = max(r[i - 1][posl], r[i - 1][posr]);
        }
    }
    for(int j = n + 1; j <= n * 2; j++) {
        int u = j, v = j;
        int ans = 0;
        for(int i = Log[3 * n]; i >= 0; i--) {
            if(max(r[i][v], r[i][u]) - min(l[i][u], l[i][v]) + 1 >= n) continue;
            int nu = rmq_l.query(l[i][u], r[i][v]);
            int nv = rmq_r.query(l[i][u], r[i][v]);
            u = nu; v = nv;
            ans += 1 << i;
        }
        ans++;
        printf("%d ", ans);
    }
    puts("");
    return 0;
}
01-04 18:58