zoukankan      html  css  js  c++  java
  • BZOJ 2002 Bounce 弹飞绵羊 —— 分块算法

    题目链接:https://vjudge.net/problem/HYSBZ-2002

    2002: [Hnoi2010]Bounce 弹飞绵羊

    Time Limit: 10 Sec  Memory Limit: 259 MB
    Submit: 12673  Solved: 6449
    [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



    题解:

    分块:将n个元素分成sqrt(n)块,每一块有sqrt(n)个元素。(可能为sqrt(n)+1块,最后一块不足sqrt(n)个元素)。

    一个元素跳到下一个元素:

    下一个元素超出范围,则直接标记。

    下一个元素不在当前块,则把当前元素的next设为下一个元素。

    下一个元素在当前块,则把当前元素的next设为下一个元素的next。


    修改:只修改在当前块内的元素,时间复杂度为O(n^0.5)。

    查询:跳块查询,每个分块最多只会被访问一次,时间复杂度为O(n^0.5)。

    综上:分块算法的时间复杂度为O(n^1.5)。



    启发:

    有些操作的修改为O(1),但是查询为O(n);或者修改为O(n),但是查询为O(1)。但是总的时间复杂度为:O(n)。

    那可不可以把修改和查询的复杂度都做到相同,就可以降低总的时间复杂度?线段树(logn)、分块算法(n^0.5)就是实例。


    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <vector>
     6 #include <cmath>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 #define ms(a,b) memset((a),(b),sizeof((a)))
    13 using namespace std;
    14 typedef long long LL;
    15 const int INF = 2e9;
    16 const LL LNF = 9e18;
    17 const int mod = 1e9+7;
    18 const int maxn = 200000+10;
    19 
    20 //step是从当前分块跳到后面的分块所需的步数,next是从(当前分块)当前位置跳到后面分块的位置
    21 int a[maxn], next[maxn], step[maxn];
    22 int n, m, block;
    23 /*
    24 block的意思是每个分块有多少个元素(但最后一个分块可能不足block个元素),
    25 如果sqrt(n)为整数,则总共有block个分块,编号为0~block-1,每个分块刚好有block个元素;
    26 如果sqrt(n)为实数,则总共有block+1个分块,编号为0~block,最后一个分块只有n-block*block个元素。
    27 */
    28 
    29 void update(int i)     //注意编号:0~n-1
    30 {
    31     int pos = i+a[i];
    32     if(pos>=n)     //跳出界
    33         next[i] = -1, step[i] = 1;
    34     else if(pos>=(i/block+1)*block)    //跳到后面的分块, i/block*block是当前分块的起始位置,i/block*block+block是下一个分块的起始位置
    35         next[i] = pos, step[i] = 1;
    36     else                                //仍在当前分块
    37         next[i] = next[pos], step[i] = step[pos]+1;
    38 }
    39 
    40 int main()
    41 {
    42     scanf("%d",&n);
    43     block = (int)sqrt(n);
    44     for(int i = 0; i<n; i++)
    45         scanf("%d",&a[i]);
    46     for(int i = n-1; i>=0; i--)
    47         update(i);
    48 
    49     scanf("%d",&m);
    50     int x, y, k;
    51     for(int i = 0; i<m; i++)
    52     {
    53         scanf("%d%d",&x,&y);
    54         if(x==1)
    55         {
    56             int ans = 0;
    57             for(int j = y; j!=-1; j = next[j])    //下一次循环即跳到后面的分块(可能是后1个,也可能是后2、后3个等等)
    58                 ans += step[j];
    59             printf("%d
    ",ans);
    60         }
    61         else
    62         {
    63             scanf("%d",&k);
    64             a[y] = k;
    65             for(int j = y; j>=(y/block)*block; j--)    //只需更新点所在的分块,y/block*block是当前分块的起始位置
    66                 update(j);
    67         }
    68     }
    69 }
    View Code
  • 相关阅读:
    微服务架构技术栈选型手册(万字长文)
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    MFC对话框中使用CHtmlEditCtrl
    ATL开发 ActiveX控件的 inf文件模板
    ActiveX: 如何用.inf和.ocx文件生成cab文件
    Xslt 1.0中使用Array
    如何分隔两个base64字符串?
    An attempt was made to load a program with an incorrect format
    JQuery 公网 CDN
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538634.html
Copyright © 2011-2022 走看看