CF1032G Chattering

CF1032G Chattering

容易发现,这道题用倍增。(秒掉题目算法,被实现卡掉。。。)
再撕烤,是区间跳区间,那么其实更新的是端点,那么维护什么就很显然。
用ST表维护一个从当前点开始 \(2^i\) 秒能跳到的左右端点,再用一个ST表维护一个区间内能跳到的左右的最远点,然后用后者更新前者。
最后一直倍增跳就完了。
时空 \(O(n \log n)\)

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;
const ll MAXN = 3e5+10;

ll N, M, Log[MAXN], val[MAXN], lb[MAXN], rb[MAXN], lt[21][MAXN], rt[21][MAXN];

struct st_biao {
    ll st[21][MAXN], v[MAXN], type;
    ll Max(ll x, ll y) {return (v[x] < v[y]) ? y : x;}
    void build(ll *now, ll n, ll _type) {
        type = _type;
        for (ll i = 1; i <= n; i++) st[0][i] = i, v[i] = type * now[i];
        for (ll i = 1; i <= Log[n]; i++)
            for (ll j = 1; j + (1LL << i) - 1 <= n; j++)
                st[i][j] = Max(st[i-1][j], st[i-1][j+(1LL << (i-1))]);
    }
    ll qmin(ll l, ll r) {
        ll dis = Log[r - l + 1];
        return Max(st[dis][l], st[dis][r - (1LL << dis) + 1]);
    }
} stl, str;

int main() {
    scanf("%lld", &N);
    for (ll i = 2; i <= 3 * N; i++) Log[i] = Log[i>>1] + 1;
    for (ll i = 1; i <= N; i++)
        scanf("%lld", val+i), val[i+N*2] = val[i+N] = val[i];
    if (N == 1) {
    	puts("0");
		return 0;
	}
    for (ll i = 1; i <= 3*N; i++) {
        lb[i] = max(1LL, i - val[i]);
        rb[i] = min(3*N, i + val[i]);
    }
    for (ll i = 0; i <= Log[3*N]; i++) rt[i][3*N] = 3*N, lt[i][1] = 1;
    for (ll i = 1; i <= 3 * N; i++) {
        lt[0][i] = lb[i];
        rt[0][i] = rb[i];
    }
    stl.build(lt[0], 3*N, -1), str.build(rt[0], 3*N, 1);
    for (ll i = 1; i <= Log[3*N]; i++) {
        for (ll j = 1; j <= 3 * N; j++) {
            ll pl = stl.qmin(lt[i-1][j], rt[i-1][j]);
            ll pr = str.qmin(lt[i-1][j], rt[i-1][j]);
            lt[i][j] = min(lt[i-1][pl], lt[i-1][pr]);
            rt[i][j] = max(rt[i-1][pl], rt[i-1][pr]);
        }
    }
    for (ll j = N+1; j <= 2*N; j++) {
        ll ans = 0;
        ll lk = j, rk = j;
        for (ll i = Log[3*N]; ~i; i--) {
            if (max(rt[i][lk], rt[i][rk]) - min(lt[i][lk], lt[i][rk]) + 1 >= N) continue;
            ll nl = stl.qmin(lt[i][lk], rt[i][rk]);
            ll nr = str.qmin(lt[i][lk], rt[i][rk]);
            lk = nl, rk = nr;
            ans += (1LL << i); 
        }
        printf("%lld ", ans + 1);
    }
    return 0;
}
posted @ 2020-10-30 21:53  Gensokyo_Alice  阅读(110)  评论(1编辑  收藏  举报