• [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的情况,你都要输出一个需要的步数,占一行。

    输入输出样例

    输入样例#1:
    4
    1 2 1 1
    3
    1 1
    2 1 1
    1 1
    输出样例#1:
    2
    3

    解题思路

    分块经典例题,把这个长度为n的序列分成√n个,对于每段小区间,我们维护以下这几个值:

    s[i]---从第i个点跳出该小区间需要的步数(step)

    t[i]---跳出该小区间后会到达哪个节点(to)

    查询时每次直接 step+=s[i],i=[i],复杂度不超过√n;

    修改时直接赋值后把当前块暴力重建,复杂度为√n;

    总时间复杂度O(m*√n) 

    总空间复杂度O(n)

    分点信息(鼠标移到方块上有详细信息)

    #1 AC 5ms/14937kB
    #2 AC 284ms/14937kB
    #3 AC 5ms/14937kB
    #4 AC 265ms/14937kB
    #5 AC 188ms/14937kB
    #6 AC 274ms/14937kB
    #7 AC 158ms/14937kB
    #8 AC 292ms/14937kB
    #9 AC 441ms/14937kB
    #10AC448ms/14937kB
     

    源代码

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cmath>
     4 #include <algorithm>
     5 #define LL long long
     6 using namespace std;
     7 const int N=200200;
     8 int k[N],bl[N],t[N],s[N]; 
     9 int blo,n,m,tot;
    10 int read(){
    11     int v=0,f=1;char c=getchar();
    12     while(c>'9'||c<'0'){if(c=='-')f*=-1;c=getchar();}
    13     while(c<='9'&&c>='0')v=v*10+c-'0',c=getchar();
    14     return v*f;
    15 }
    16 void reset(int x){
    17     for(int i=min(n,x*blo);i>=(x-1)*blo+1;i--){
    18         int to=i+k[i];
    19         if(to>min(n,x*blo))s[i]=1,t[i]=to;
    20         else {
    21             s[i]=s[to]+1;
    22             t[i]=t[to];
    23         }
    24     }
    25 }
    26 int query(int x){
    27     int rtn=0;
    28     while(x<=n){
    29         rtn+=s[x];
    30         x=t[x];    
    31     }
    32     return rtn;
    33 }
    34 void change(int x,int v){
    35     k[x]=v;
    36     reset(bl[x]);
    37 }
    38 int main(){
    39     n=read();blo=sqrt(n);
    40     for(int i=1;i<=n;i++){
    41         k[i]=read();
    42         bl[i]=(i-1)/blo+1;
    43     }    44     tot=bl[n];
    45     for(int i=1;i<=tot;i++)reset(i);
    46     m=read();
    47     while(m--){
    48         int opt,p,v;
    49         opt=read();
    50         if(opt==1){
    51             p=read();
    52             printf("%d
    ",query(p+1));
    53         }
    54         if(opt==2){
    55             p=read();v=read();
    56             change(p+1,v);
    57         }
    58     }
    59     return 0;
    60 } 
  • 相关阅读:
    时光流年(4)向往
    Vue.js入门(9)组件插槽
    时光流年(3)古韵
    Java面试题(12)哈希表
    Java面试题(11)Java中hashCode方法的作用
    Java面试题(10)Java中==、equals()、compareTo()的区别
    Java MyBatis-Plus(1)
    Vue.js入门(8)watch、computed和methods之间的区别
    Java面试题(9)常用工具
    Java MyBatis3(11)逆向工程--MyBatis Generator
  • 原文地址:https://www.cnblogs.com/Anoxiacxy/p/6866755.html
Copyright © 2020-2023  润新知