zoukankan      html  css  js  c++  java
  • Bzoj 2002: [Hnoi2010]Bounce 弹飞绵羊(分块)

    2002: [Hnoi2010]Bounce 弹飞绵羊
    Time Limit: 10 Sec Memory Limit: 259 MB
    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

    /*
    分块.
    没有修改的话我们可以O(n)暴力递推出每个块的贡献.
    然后O(1)查询.
    这个题有修改操作如果那样做的话复杂度可能会到O(n).
    然后我们可以分块O(√n)的时间内完成这两个操作.
    对于每个点维护一个跳出这个块的第一个位置和在这个中的移动次数.
    修改操作的时候要倒序修改
    这样倒序递推比较方便....
    splay启发式合并什么的以后再写. 
    */
    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define MAXN 200001 
    using namespace std;
    int next[MAXN],belong[MAXN],n,m,ans,k[MAXN],len,s[MAXN];
    int read()
    {
        int 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-48,ch=getchar();
        return x*f;
    }
    void slove(int x)
    {
        int tot,pos;
        for(int i=(x-1)*len+1;i<=min(n,x*len);i++)
        {
            tot=0,pos=i;//位置
            while(pos<=n&&belong[pos]==x) tot++,pos+=k[pos];
            s[i]=tot,next[i]=pos;
        }
        return ;
    }
    int query(int x)
    {
        ans=0;
        for(int i=x;i<=n;i=next[i]) ans+=s[i];
        return ans;
    }
    void _union(int x,int y)
    {
        k[x]=y;
        for(int i=x;i>=(belong[x]-1)*len+1;i--)//倒序递推 
        {
            if(i+k[i]>belong[x]*len) s[i]=1,next[i]=i+k[i];
            else s[i]=s[i+k[i]]+1,next[i]=next[i+k[i]];
        }
        return ;
    }
    int main()
    {
        int x,y,z;
        n=read();len=sqrt(n);
        for(int i=1;i<=n;i++)
        {
            k[i]=read();
            belong[i]=(i-1)/len+1;//每块的
        }
        for(int i=1;i<=belong[n];i++) slove(i);
        m=read();
        for(int i=1;i<=m;i++)
        {
            z=read(),x=read();x++;
            if(z&1) printf("%d
    ",query(x));
            else y=read(),_union(x,y);
        }
        return 0;
    }
  • 相关阅读:
    iOS:真机调试
    iOS:MBProgressHUD的基本使用
    CocoaPods安装小步骤
    PictureBox 双缓冲防止闪屏
    两招小办法对付宝宝发烧、咳嗽。超级管用哈
    (转)经纬度坐标转换为屏幕坐标
    解决eclipse不识别Android手机的问题
    利用FFmpeg将RTSP转码成RTMP发布在RED5
    vlc做转发的命令
    字符编码
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068060.html
Copyright © 2011-2022 走看看