分块-洛谷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{//x,y是区间范围
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);
}
}
}