zoukankan      html  css  js  c++  java
  • bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊

    2002: [Hnoi2010]Bounce 弹飞绵羊

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

    分块

    用两个数组out和where,out表示从当前点再跳几步能跳出当前块,where记录跳到下一块的哪个点就可以模拟了

    查询O(sqrt(n)),修改复杂度也是sqrt(n)
    总复杂度 O(m*sqrt(n))

    #include<cstdio>
    #include<cmath>
    
    
    const int N=2000004;
    int a[N],where[N],out[N],belong[N],left[500],right[500];
    //out记录再走几步出块,where记录出块后到达的点。
    int n,m;
    
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    
    inline void divide(int x)
    {
        for(int i=1;i<=x;i++)
        left[i]=right[i-1]+1,right[i]=i*x;
        right[x]=n;
        for(int i=1;i<=x;i++)
            for(int j=left[i];j<=right[i];j++)
            belong[j]=i;
        for(int i=n;i>=1;i--)
        {
            if(where[i]>right[belong[i]])out[i]=1;
            else out[i]=out[where[i]]+1,where[i]=where[where[i]];
        }
    }
    
    inline void query(int x)
    {
        int ans=0;
        while(x<=n)
        {
            ans+=out[x],x=where[x];
        }
        printf("%d
    ",ans);
    }
    
    inline void modify(int x,int y)
    {
        int i,j;
        int tmp=belong[x],l=left[tmp],r=right[tmp];
        a[x]=x+y;
        if(a[x]>r)out[x]=1,where[x]=a[x];
        else out[x]=out[a[x]]+1,where[x]=where[a[x]];
        for(i=x-1;i>=l;i--)
        {
            if(a[i]<=x)
            out[i]=out[a[i]]+1,where[i]=where[a[i]];
        }
    }
    
    int main()
    {
        n=read();
        int x=sqrt(n);
        for(int i=1;i<=n;i++)
        a[i]=read(),where[i]=i+a[i],a[i]=where[i];
        
        divide(x);
        m=read();
        int i,j,k;
        while(m--)
        {
            i=read();
            if(i==1)
            {
                j=read();
                j++;
                query(j);
            }
            else 
            {
                j=read(),k=read();
                j++;
                modify(j,k);
            }
        }
        return 0;
    }
  • 相关阅读:
    021.day21 反射 Class类 反射常用操作
    020.day20 线程概述 多线程优缺点 线程的创建 线程常用方法 生命周期 多线程同步
    019.day19 缓冲流 对象流 标准输入输出流
    018.day18 map集合如何实现排序 File类 IO流 字节流 字符流 编码
    017.day17 Map接口 克隆 treeSet集合排重缺陷
    016.day16 HashSet TreeSet 比较器Comparable Comparator
    015.day15
    014.day14
    013.day13
    线程
  • 原文地址:https://www.cnblogs.com/sssy/p/6879657.html
Copyright © 2011-2022 走看看