您的位置:首页 > 其它

bzoj2002: [Hnoi2010]Bounce 弹飞绵羊(分块)

2017-08-15 10:59 393 查看
题意:

给一个序列,元素i的值x代表这个元素能跳到i+x位置。m次询问,对每个询问q,问q元素经过几次跳跃能跳出序列。询问中还有修改操作。

思路:

直接暴力的话,查询操作时间复杂度是O(n),修改操作O(1),最坏总时间O(m*n);题目意思就是序列中某个元素跳出这个序列需要的次数,那么我们可以把序列分割,对每个子序列,记录该序列中的每个元素跳出该序列需要的次数e[i],以及跳出这个序列后的位置en[i];如果把序列分成根号N块,那么查询和修改操作的时间都是根号N了。总时间O(m*根号n)

代码:

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;
const int maxn = 200000+10;
int arr[maxn],e[maxn],en[maxn];
int main()
{
int n,m;
scanf("%d",&n);
for(int i = 0;i<n;i++)
{
scanf("%d",&arr[i]);
}
int len = sqrt(1.0*n);
for(int i = n-1;i>=0;i--)
{
int lin = min((i/len+1)*len,n);
int num = 1;
int pos = i;
pos += arr[i];
while(pos<lin)
{
num += e[pos];
pos = en[pos];
}
e[i]= num;
en[i] = pos;
}
scanf("%d",&m);
while(m--)
{
int type;
scanf("%d",&type);
if(type==1)
{
int pos;
scanf("%d",&pos);
int ans = 0;
while(pos<n)
{
ans += e[pos];
pos = en[pos];
}
printf("%d\n",ans);
}
else
{
int q,v;
scanf("%d%d",&q,&v);
arr[q] = v;
int lin = min((q/len+1)*len,n);
for(int i = q;i>=(q/len)*len;i--)
{
int num = 1;
int pos = arr[i]+i;
while(pos<lin)
{
num+=e[pos];
pos = en[pos];
}
e[i] = num;
en[i] = pos;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: