• 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;
    }
  • 相关阅读:
    SSL证书的生成方法
    某些系统文件破坏后的修复方式
    dd命令的使用简介
    浅谈访问控制列表(ACL)
    发送端usleep(900)单线程带宽
    1024个读出线程的测试结果
    寻找ROS取数的瓶颈:思路整理(2)
    ROS:32个接收进程的接收带宽
    ROS: 将接收端的接收函数注释掉,TCP只发送,不接受数据时的recv-Q和send-Q长度实验
    ROS:16个接收进程的接收带宽
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068060.html
Copyright © 2020-2023  润新知