• bzoj 2002 [Hnoi2010]Bounce 弹飞绵羊 分块


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2002

    2002: [Hnoi2010]Bounce 弹飞绵羊

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 11719  Solved: 5923
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行包含一个整数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

    Output

    对于每个i=1的情况,你都要输出一个需要的步数,占一行。

    Sample Input

    4
    1 2 1 1
    3
    1 1
    2 1 1
    1 1

    Sample Output

    2
    3

    思路:

    分块。
    分成K个块后,维护如下两个内容:
    1.F[i],表示第i个点多少歩后会跳出这个块。
    2.S[i],表示第i个点跳出块以后会跳到哪里。
    对于询问,最多会走K个块就能找到答案。O(K)。
    对于修改,最多修改块内的N/K个元素就可以。O(N/K)。

    修改只会影响当前块内要修改的位置的前面可以跳到这个位置的点。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define MS(a) memset(a,0,sizeof(a))
    #define MP make_pair
    #define PB push_back
    const int INF = 0x3f3f3f3f;
    const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
    inline ll read(){
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    //////////////////////////////////////////////////////////////////////////
    const int maxn = 2e5+10;
    
    int n,num,block,belong[maxn],a[maxn],f[maxn],s[maxn],le[maxn],ri[maxn];
    
    void build(){
        num = sqrt(n*1.0);
        block = n/num;
        if(n%num) block++;
        for(int i=1; i<=n; i++){
            belong[i] = (i-1)/num+1;
        }
        for(int i=1; i<=block; i++){
            le[i] = (i-1)*num+1;
            ri[i] = i*num;
        }
        ri[block] = n;
        for(int i=block; i>=1; i--){
            for(int j=ri[i]; j>=le[i]; j--){
                int t = j+a[j];
                f[j] = (t>ri[i] ? 1 : f[t]+1);
                s[j] = (t>ri[i] ? t : s[t]);
            }
        }
    }
    
    int que(int x){
        int res = 0;
        while(x <= n){
            res += f[x];
            // cout << x << endl;
            x = s[x];
            // cout << x << " ====
    ";
        }
        return res;
    }
    
    void upd(int x,int y){
        int id = belong[x];
        int i = x, cnt = 0;
        a[x] = y;
        while(i <= ri[id]){
            i = i+a[i];
            cnt++;
        }
        f[x] = cnt;
        s[x] = i;
        for(int j=x-1; j>=le[id]; j--){
            int t = j+a[j];
            f[j] = (t>ri[id] ? 1: f[t]+1);
            s[j] = (t>ri[id] ? t : s[t]);
        }
        // cout << f[x] << " " << s[x] << " " << ri[id] << endl;
    }
    
    int main(){
        n = read();
        for(int i=1; i<=n; i++)
            a[i] = read();
        build();
        // cout << block << endl;
        // for(int i=1; i<=n; i++)
        //     cout << f[i] << " " << s[i] << endl;
        int q = read();
        while(q--){
            int op = read();
            if(op == 1){
                int x = read(); x++;
                printf("%d
    ",que(x));
            }else{
                int x,y; scanf("%d%d",&x,&y);
                x++;
                upd(x,y);
            }
        }
    
        return 0;
    }
  • 相关阅读:
    BZOJ 1093: [ZJOI2007]最大半连通子图
    BZOJ 1406: [AHOI2007]密码箱
    BZOJ 1073: [SCOI2007]kshort
    BZOJ 1857: [Scoi2010]传送带
    AC日记——天天爱跑步 洛谷 P1600
    AC日记——[Sdoi2010]粟粟的书架 bzoj 1926
    AC日记——The Shortest Path in Nya Graph hdu 4725
    AC日记——文化之旅 洛谷 P1078
    AC日记——【模板】分块/带修改莫队(数颜色) 洛谷 P1903
    AC日记——大爷的字符串题 洛谷 P3709
  • 原文地址:https://www.cnblogs.com/yxg123123/p/7470510.html
Copyright © 2020-2023  润新知