1. 程式人生 > >洛谷P3203彈飛綿羊

洛谷P3203彈飛綿羊

+= %d 分塊 printf 神奇 lse init str ios

傳送門啦

非常神奇的分塊大法。

每塊分 √N 個元素 , 預處理出來:對於每個點,記錄兩個量:一個是它要彈幾次才能出它所在的這個塊,另外一個是它彈出這個塊後到哪個點。

查詢操作:一塊一塊跳過去 單次復雜度 O(√N)

修改操作:只需要把相應的塊改一遍就好了 這個也是O(√N)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 200005;
const int maxm = 100005;

inline int read(){
    char ch = getchar();
    int f = 1 , x = 0;
    while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch =getchar();}
    while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
    return x * f;
}

int n,a[maxn],m,flag,x,y,ans;
int l[maxn],r[maxn],cnt,belong[maxn],to[maxn],step[maxn];

void init(){
    int t = sqrt(n);
    if(n / t)  cnt = n / t + 1;
    else cnt = n / t;
    for(int i=1;i<=cnt;i++){
        l[i] = r[i-1] + 1;
        r[i] = min(l[i] + t - 1 , n);
    }
    int x = 1;
    for(int j=1;j<=n;j++){ 
        belong[j] = x;
        if(j == r[x] && x <= cnt)  x++;
    }
    for(int i=n;i>=1;i--){
        to[i] = i + a[i];
        if(to[i] > r[belong[i]])  step[i] = 1;
        else {
            step[i] = step[to[i]] + 1;
            to[i] = to[to[i]];
        }
    }
}

int main(){
    n = read();
    for(int i=1;i<=n;i++)  a[i] = read();
    init();
    m = read();
    while(m--){
        ans = 0;
        flag = read();
        if(flag == 1){
            x = read(); x++;
            while(x <= n){
                ans += step[x];
                x = to[x];
            }
            printf("%d\n",ans);
        }
        else {
            x = read(); y = read();
            x++;
            a[x] = y;
            for(int i=r[belong[x]];i>=l[belong[x]];i--){
                to[i] = i + a[i];
                if(to[i] > r[belong[i]]) step[i] = 1;
                else {
                    step[i] = step[to[i]] + 1;
                    to[i] = to[to[i]];
                }
            }
        }
    }
    return 0;
}

洛谷P3203彈飛綿羊