分块-洛谷P3203 [HNOI2010]BOUNCE 弹飞绵羊

https://www.luogu.org/problem/show?pid=3203#sub
这道题第一次TLEl,然后改了改变成AC;
所以说这种题目,时限卡得很紧,一定要思考理论复杂度和常数的问题;
据说LCT
我用分块做,其实我并不是怎么理解分块的用途,貌似能用分块做,时限能接受,就可以分块暴力;

  • 首先考虑两种暴力做法:对于操作1,直接修改,查询的时候O(N)模拟。或者修改的时候O(N)将每个位置的答案算出来,查询的时候O(1)回答
    我们可以用分块来平衡两种做法的复杂度:
    对于每一块,我们可以使用第二种暴力预处理出每个位置的答案(跳出这个块的步数以及跳出块之后的位置),在修改的时候只需要将这一块整个重新计算,时间复杂度O( )。
    在查询的时候使用第一种暴力,由于利用预处理信息每次至少可以跳过一段,所以时间复杂度O(N/ )。
    总时间复杂度O(N* )。
    //空的地方是sqrt(N)

xxy’s↑
这个是我们学长告诉我们的;
妥妥;
思路应该很清晰了,第一种暴力大家都会把;
那第二种暴力咋么搞呢,我们只要从后往前地推就好了;
结合成分块就好啦啊;
在这题里,分块就变成了核心,大家的分块技能应有所提升;

#include<cstdio>//cfb
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
struct kuai{//xy是区间范围 
    int x,y;
}q[448];
struct cs{
    int v,x,y,z;//v是读入,x表示在那个块,y表示跳出块要几次,z是跳出后到哪里 
}a[200001];
int n,m,x,y,z,nn,ll,sum,ans;//ll是块的数量,有些变量没用的; 
void resetkuai(int k){//重置一个块,更新a[i].y a[i].z; 
    for(int i=q[k].y;i>=q[k].x;i--)//暴力地推 
        if(i+a[i].v>q[k].y){
            a[i].y=1;a[i].z=i+a[i].v;
        }else{
            a[i].y=a[i+a[i].v].y+1;a[i].z=a[i+a[i].v].z;
        }
}
void fenkuai(){//这是我的分块函数,非常方便,无需预先计算块数 
    int l=1,k=sqrt(n);
    while(l<=n){
        q[++ll].x=l;
        q[ll].y=min(n,l+k-1);
        l+=k;
        for(int i=q[ll].x;i<=q[ll].y;i++)a[i].x=ll;
        resetkuai(ll);
    }
}
void outit(int x){//无脑暴力求解 
    int ans=0;
    while(x<=n){
        ans+=a[x].y;
        x=a[x].z;
    }
    printf("%d\n",ans);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].v);
    fenkuai();
    scanf("%d",&m);
    while(m--){
        scanf("%d",&z);
        if(z==2){
            scanf("%d%d",&x,&y);
            x++;
            a[x].v=y;
            resetkuai(a[x].x);
        }else{
            scanf("%d",&x);
            x++;//因为读入从0开始
            outit(x);
        }
    }
}
posted @ 2017-02-23 13:02  largecube233  阅读(130)  评论(0编辑  收藏  举报