——BZOJ2002 php
某天,Lostmonkey發明了一種超級彈力裝置,爲了在他的綿羊朋友面前顯擺,他邀請小綿羊一塊兒玩個遊戲。遊戲一開始,Lostmonkey在地上沿着一條直線擺上n個裝置,每一個裝置設定初始彈力系數ki,當綿羊達到第i個裝置時,它會日後彈ki步,達到第i+ki個裝置,若不存在第i+ki個裝置,則綿羊被彈飛。綿羊想知道當它從第i個裝置起步時,被彈幾回後會被彈飛。爲了使得遊戲更有趣,Lostmonkey能夠修改某個彈力裝置的彈力系數,任什麼時候候彈力系數均爲正整數。數組
第一行包含一個整數\(n\),表示地上有\(n\)個裝置,裝置的編號從\(0\)到\(n-1\),接下來一行有\(n\)個正整數,依次爲那\(n\)個裝置的初始彈力系數。第三行有一個正整數\(m\),接下來\(m\)行每行至少有兩個數\(i\)、\(j\),若\(i=1\),你要輸出從\(j\)出發被彈幾回後被彈飛,若\(i=2\)則還會再輸入一個正整數\(k\),表示第j個彈力裝置的係數被修改爲\(k\)。對於\(20\%\)的數據\(n,m \le 10000\),對於\(100\%\)的數據\(n \le 200000\),\(m \le 100000\)spa
對於每一個i=1的狀況,你都要輸出一個須要的步數,佔一行。code
4 1 2 1 1 3 1 1 2 1 1 1 1
2 3
這道題的正解是LCT?
不過這是省選題,必定有其餘的解法,這裏就有一個分塊作法。
O(n)維護兩個數組to和outto,to表明每一個位置跳到塊內最後一個位置的最少步數,outto表示這個位置跳到第二個塊的新位置。這兩個數組倒着維護。
而後就能作了。
詢問和修改的時間複雜度都是\(O(\sqrt n)\),由於一共\(\sqrt n\)個塊,每一個塊內\(\sqrt n\)個元素。遊戲
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 2e5 + 5; int seq[maxn]; int blo[10005]; int to[maxn]; int outto[maxn]; int m,n; int cnt,num,cntt=1; int qpos(int x) { return x % cnt == 0 ? x / cnt : x / cnt + 1; } int qlast(int x) { if(qpos(x) == num) return n; return cnt * qpos(x); } int qfirst(int x) { return cnt * (qpos(x) - 1) + 1; } int main() { n = read(); cnt = sqrt(n); num = qpos(n); for(int i=1;i<=n;i++) seq[i] = read(); for(int i=n;i>=1;i--) { if(i + seq[i] > qlast(i)) { to[i] = i + seq[i]; outto[i] = 1; } else { to[i] = to[i+seq[i]]; outto[i] = outto[i+seq[i]] + 1; } } // printf("\n***\n"); // for(int i=1;i<=n;i++) // printf("%d ",to[i]); // printf("\n"); // for(int i=1;i<=n;i++) // printf("%d ",outto[i]); // printf("\n***\n"); m = read(); for(int ct=1;ct<=m;ct++) { int ju; ju = read(); if(ju == 1) { int x,ans; x = read(); x+=1; ans = outto[x]; x = to[x]; while(x <= n) { ans += outto[x]; x = to[x]; } printf("%d\n",ans); } else { int x,k; x = read(); k = read(); x+=1; seq[x] = k; for(int i=x;i>=qfirst(x);i--) { if(i + seq[i] > qlast(i)) { to[i] = i + seq[i]; outto[i] = 1; } else { to[i] = to[i+seq[i]]; outto[i] = outto[i+seq[i]] + 1; } } } } return 0; }