【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;
}
时间: 2024-08-08 08:55:18

【bzoj2002】弹飞绵羊(分块)的相关文章

bzoj2002 弹飞绵羊 分块

这道题是分块的初尝试 讲给定的区间n进行分块处理 这个每次修改的复杂的只有logn 很方便 代码是学黄学长的 http://hzwer.com/3505.html 当然里面还是有一定我自己的想法在里面的 嫌我代码丑的可以去看黄学长的咯 #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cstdlib> using namespace st

【bzoj2002】[Hnoi2010]Bounce 弹飞绵羊 分块

[bzoj2002][Hnoi2010]Bounce 弹飞绵羊 2014年7月30日8101 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞.绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞.为了使得游戏更有趣,Los

【codevs2333】&amp;【BZOJ2002】弹飞绵羊[分块]

我其实是在codevs上看到它的题号后才去做这道题的...2333... 题目传送门:codevs:http://codevs.cn/problem/2333/ bzoj:http://www.lydsy.com/JudgeOnline/problem.php?id=2002 题意已经说的很清晰了,蓝鹅--我不会做. 看题解有两种写法:分块和link-cut tree.但是lct我不会,只能用分块了. 但是怎么分块呢? 我们想一下有什么暴力写法.一种是记录每个反弹装置能往后弹多长距离,这样效率是

BZOJ 2002 Bounce 弹飞绵羊(分块|暴力|)(困难)

Bounce 弹飞绵羊 Time Limit:10000MS     Memory Limit:265216KB     64bit IO Format:%lld & %llu Submit Status Practice HYSBZ 2002 Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后

bzoj2002 弹飞绵羊 LCT

2002: [Hnoi2010]Bounce 弹飞绵羊 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 6706  Solved: 3522[Submit][Status][Discuss] Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki

bzoj2002: [Hnoi2010]Bounce 弹飞绵羊 [分块][LCT]

Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞.绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞.为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数. Input 第一行

BZOJ-2002-Bounce弹飞绵羊-分块

描述 Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞.绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞.为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数. 分析 分块, 维护 i 位置的绵羊经过几次弹出该块(f[]), 以及弹出后落在哪个位置(arv[]). 这样就可以在 n√n 的时间内完成本题. 遇到查

[HNOI2010][BZOJ2002] 弹飞绵羊 - LCT

Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置设定初始弹力系数ki,当绵羊达到第i个装置时,它会往后弹ki步,达到第i+ki个装置,若不存在第i+ki个装置,则绵羊被弹飞.绵羊想知道当它从第i个装置起步时,被弹几次后会被弹飞.为了使得游戏更有趣,Lostmonkey可以修改某个弹力装置的弹力系数,任何时候弹力系数均为正整数. Input & O

B2002 [Hnoi2010]Bounce 弹飞绵羊 分块

原来做过,看大家都做这道题都热情高涨,沈爷爷debug这道题4天,作为告诉他这个题的人,我还有点不好意思...我自己也就做了一个小时. 其实这个题思路还好,就是维护每个点的出块次数和跳出块的位置,然后访问的时候直接调用块. 这个题还有一个比较坑的地方,就是每个绵羊只有到队尾的时候才会被弹飞,所以不用担心在中间停止的情况. 题干: Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿

【bzoj2002】弹飞绵羊——分块

这道题是很简单的分块吧,统计每个块里要中转的次数(即st数组),最后输出即可. 如果修改某个弹力装置的弹力系数,那么要从这个装置开始往回走到这一块的最左端(即l[belong[b]]),修改相对应的st数组和pt数组,它前面的块和后面的块都不受影响(因为st统计的是走到这一步到走出这一个装置所属的块所需的步数). 具体实现细节看代码: #include<cstdio> #include<cstring> #include<cmath> #include<iostr