題解-彈飛綿羊 (HNOI2015)
阿新 • • 發佈:2018-07-12
bll include freopen != hnoi2015 style 來源 namespace tdi
來源 HZOI
LCT 模板題,分塊也很優秀。
分塊做法
維護每個點到第一次跳到下一個塊時的跳躍次數,並記錄其跳到下一個塊的第一個點。
註意常見的分塊玄學操作 n = min(sqrt(N), 100) 和 n = sqrt(N)*1.23 。
1 #include <stdio.h> 2 #include <algorithm> 3 #include <math.h> 4 5 using namespace std; 6 7 const int _N = 220000; 8 9 int N, n, M; 10 int A[_N], f[_N], des[_N];View Code11 12 inline int dn(int v) { return (v-1)/n*n+1; } 13 14 inline int up(int v) { return min(N, (v-1)/n*n+n); } 15 16 int main() 17 { 18 int i; 19 scanf("%d", &N); 20 for (i = 1; i <= N; ++i) 21 scanf("%d", &A[i]); 22 scanf("%d", &M); 23 24 n = min(N, int(sqrt(N+0.5)*1.32)); 25 26 for (i = N; i >= 1; --i) 27 if (i+A[i] > up(i)) f[i] = 1, des[i] = min(i+A[i], N+1); 28 else f[i] = f[i+A[i]]+1, des[i] = des[i+A[i]]; 29 30 for (i = 1; i <= M; ++i) { 31 int ins, k; 32 scanf("%d%d", &ins, &k), ++k;33 if (ins == 1) { 34 int cnt = 0, j = k; 35 while (j != N+1) { 36 cnt += f[j]; 37 j = des[j]; 38 } 39 printf("%d\n", cnt); 40 } else { 41 int j = k; 42 scanf("%d", &A[k]); 43 for (int t = j; t >= dn(j); --t) 44 if (t+A[t] > up(t)) f[t] = 1, des[t] = min(t+A[t], N+1); 45 else f[t] = f[t+A[t]]+1, des[t] = des[t+A[t]]; 46 } 47 } 48 49 return 0; 50 }
LCT做法
1 #include <stdio.h> 2 #include <stack> 3 4 using namespace std; 5 6 const int _N = 220000; 7 8 typedef long long LL; 9 10 stack<LL> S; 11 LL Sum[_N], L[_N], R[_N], Dad[_N], Rev[_N], J[_N], W[_N]; 12 13 inline void Update(LL x) { Sum[x] = Sum[L[x]] + W[x] + Sum[R[x]]; return; } 14 15 inline bool IsRoot(LL x) { return L[Dad[x]] != x && R[Dad[x]] != x; } 16 17 void Zig(LL x) 18 { 19 LL y = Dad[x], z = Dad[y]; 20 if (!IsRoot(y)) L[z] == y ? L[z] = x : R[z] = x; 21 Dad[x] = z; 22 L[y] = R[x], Dad[R[x]] = y; 23 R[x] = y, Dad[y] = x; 24 Update(y), Update(x); 25 return; 26 } 27 28 void Zag(LL x) 29 { 30 LL y = Dad[x], z = Dad[y]; 31 if (!IsRoot(y)) L[z] == y ? L[z] = x : R[z] = x; 32 Dad[x] = z; 33 R[y] = L[x], Dad[L[x]] = y; 34 L[x] = y, Dad[y] = x; 35 Update(y), Update(x); 36 return; 37 } 38 39 inline void PushDown(LL x) { 40 if (Rev[x]) { 41 Rev[L[x]] ^= 1, Rev[R[x]] ^= 1, Rev[x] ^= 1; 42 swap(L[x], R[x]); 43 } 44 return; 45 } 46 47 void Splay(LL x) 48 { 49 S.push(x); 50 for (LL i = x; !IsRoot(i); i = Dad[i]) S.push(Dad[i]); 51 while (!S.empty()) PushDown(S.top()), S.pop(); 52 53 while (!IsRoot(x)) { 54 LL y = Dad[x], z = Dad[y]; 55 if (!IsRoot(y)) { 56 if (L[z] == y) L[y] == x ? (Zig(y), Zig(x)) : (Zag(x), Zig(x)); 57 else R[y] == x ? (Zag(y), Zag(x)) : (Zig(x), Zag(x)); 58 } else { 59 L[y] == x ? Zig(x) : Zag(x); 60 } 61 } 62 63 return; 64 } 65 66 void Access(LL x) 67 { 68 LL t = 0; 69 while (x) { 70 Splay(x), R[x] = t, Update(x); 71 t = x, x = Dad[x]; 72 } 73 return; 74 } 75 76 LL FindRoot(LL x) { Access(x), Splay(x); while (L[x]) x = L[x]; return x; } 77 78 void MakeRoot(LL x) { Access(x), Splay(x), Rev[x] ^= 1; return; } 79 80 void Cut(LL x, LL y) { MakeRoot(x), Access(y), Splay(y), L[y] = Dad[x] = 0; Update(y); return; } 81 82 void Link(LL x, LL y) { MakeRoot(x), Dad[x] = y; } 83 84 int main() 85 { 86 // freopen("1.txt", "r", stdin); 87 LL N, Q, i, Suicide; 88 scanf("%lld", &N), Suicide = N+1; 89 // W[Suicide] = Sum[Suicide] = 1; 90 for (i = 1; i <= N; ++i) scanf("%lld", &J[i]), W[i] = 1, Sum[i] = 1; 91 for (i = 1; i <= N; ++i) 92 if (i+J[i] <= N) Link(i, i+J[i]); 93 else Link(i, Suicide); 94 95 scanf("%lld", &Q); 96 while (Q--) { 97 LL ins, t1, t2; 98 scanf("%lld%lld", &ins, &t1), ++t1; 99 if (ins == 1) { 100 MakeRoot(Suicide), Access(t1), Splay(t1); 101 printf("%lld\n", Sum[t1]); 102 } else if (ins == 2) { 103 scanf("%lld", &t2); 104 if (t1+J[t1] <= N) Cut(t1, t1+J[t1]); 105 else Cut(t1, Suicide); 106 J[t1] = t2; 107 if (t1+J[t1] <= N) Link(t1, t1+J[t1]); 108 else Link(t1, Suicide); 109 } 110 } 111 return 0; 112 }View Code
NKOJ2381
P2381【HNOI2010】彈飛綿羊 | |
|
問題描述
某天,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<=10000,對於100%的數據n<=200000,m<=100000
輸出格式
對於每個i=1的情況,你都要輸出一個需要的步數,占一行。
樣例輸入
4
1 2 1 1
3
1 1
2 1 1
1 1
樣例輸出
2
3
來源 HZOI
題解-彈飛綿羊 (HNOI2015)