bzoj2002弹飞绵羊(分块)
Posted CzYoL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj2002弹飞绵羊(分块)相关的知识,希望对你有一定的参考价值。
题目分析
题意:每个点都有一个值$v_i$,从一个点出发,每走到一个点,会跳到i+vi的位置,问需要跳多少次能跳出n?带修改。
此题可以用lct做,此处使用了分块:将序列分块后,每个点记录从此点最少跳几次能跳出当前块,和跳出后到达的位置,倒叙可以优化。
这样询问时只要一直跳至多$\sqrt{n}$个块就能知道答案。
对于修改操作,只需将修改点和修改点之前的当前块元素重新使用上述处理,同样倒叙可以优化。
code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int N = 2e5 + 5; int n, m, S; int blkCnt, blk[N], bl[500], br[500]; long long val[N], step[N], des[N]; inline int read(){ int i = 0, f = 1; char ch = getchar(); for(; (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘; ch = getchar()); if(ch == ‘-‘) f = -1, ch = getchar(); for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar()) i = (i << 3) + (i << 1) + (ch - ‘0‘); return i * f; } inline long long readL(){ long long i = 0, f = 1; char ch = getchar(); for(; (ch < ‘0‘ || ch > ‘9‘) && ch != ‘-‘; ch = getchar()); if(ch == ‘-‘) f = -1, ch = getchar(); for(; ch >= ‘0‘ && ch <= ‘9‘; ch = getchar()) i = (i << 3) + (i << 1) + (ch - ‘0‘); return i * f; } inline void wr(long long x){ if(x < 0) putchar(‘-‘), x = -x; if(x > 9) wr(x / 10); putchar(x % 10 + ‘0‘); } inline void init(){ bl[blkCnt = 1] = 1; for(int i = 1; i <= n; i++){ if(i % S == 0){ br[blkCnt] = i; blk[i] = blkCnt; if(i + 1 <= n){ bl[++blkCnt] = i + 1; continue; } } blk[i] = blkCnt; } br[blkCnt] = n; } int main(){ n = read(), S = sqrt(n); for(int i = 1; i <= n; i++) val[i] = readL(); init(); for(int i = n; i >= 1; i--){ int tmp = i; bool flag = false; step[i] = 0; while(tmp + val[tmp] <= br[blk[i]]){ tmp += val[tmp], step[i]++; if(step[tmp]){ step[i] += step[tmp], des[i] = des[tmp], flag = true; break; } } if(!flag) des[i] = tmp + val[tmp], step[i]++; } m = read(); for(int t = 1; t <= m; t++){ int opt = read(); if(opt == 1){ int src = read() + 1, ans = 0, tmp; tmp = src; while(des[tmp] <= n) ans += step[tmp], tmp = des[tmp]; ans += step[tmp]; wr(ans), putchar(‘\n‘); } else{ int pos = read() + 1, value = readL(); if(val[pos] == value) continue; val[pos] = value; for(int i = bl[blk[pos]]; i <= pos; i++) step[i] = 0; for(int i = pos; i >= bl[blk[pos]]; i--){ int tmp = i; bool flag = false; while(tmp + val[tmp] <= br[blk[pos]]){ tmp += val[tmp], step[i]++; if(step[tmp]){ step[i] += step[tmp], des[i] = des[tmp], flag = true; break; } } if(!flag) des[i] = tmp + val[tmp], step[i]++; } } } return 0; }
以上是关于bzoj2002弹飞绵羊(分块)的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ 2002][Hnoi2010]Bounce 弹飞绵羊(分块)
bzoj 2002[Hnoi2010]Bounce 弹飞绵羊(分治分块)