分块算法&BZOJ2002

题目传送门

第一次接触分块......

分块查找是折半查找和顺序查找的一种改进方法,分块查找由于只要求索引表是有序的,对块内节点没有排序要求,因此特别适合于节点动态变化的情况。

分块修改理论复杂度为O(N/M),M为块的大小,有基本不等式得M=Sqrt(N)时较优。

分块将原数组分为M块,对M块的信息进行维护。

这道题每个点记录一个它跳到下一个不是同一块的点是哪个点及需要几步跳到那个点。

code:

/**************************************************************
Problem: 2002
User: yekehe
Language: C++
Result: Accepted
Time:1648 ms
Memory:3956 kb
****************************************************************/ #include <cstdio>
#include <cmath>
using namespace std; int read()
{
char c;while(c=getchar(),c<''||c>'');
int x=c-'';while(c=getchar(),c>=''&&c<='')x=x*+c-'';
return x;
} const int MAXN=;
int N,M,Q,a[MAXN];
int belong[MAXN],nxt[MAXN],J[MAXN]; int Query(int x)
{
int tot=;
while(x<=N){
tot+=J[x];
x=nxt[x];
}
return tot;
} void Change(int x,int y)
{
int l=(belong[x]-)*M+,r=belong[x]*M;
a[x]=y;
for(int i=x;i>=l;i--){
if(i+a[i]>r)nxt[i]=i+a[i],J[i]=;
else nxt[i]=nxt[i+a[i]],J[i]=J[i+a[i]]+;
}
return ;
} int main()
{
N=read();M=sqrt(N);
if(M*M<N)M++;
register int i,j;
for(i=;i<=N;i++)a[i]=read();
j=;
for(i=;i<=M;i++)
for(;j<=i*M&&j<=N;j++)
belong[j]=i;
for(i=;i<=N;i++){
int Ks=;
for(j=i;j<=N&&belong[j]==belong[i];j+=a[j])Ks++;
nxt[i]=(j>N?N+:j);
J[i]=Ks;
}
Q=read();
while(Q--){
int o=read(),x=read();
if(o==)printf("%d\n",Query(x+));
else Change(x+,read());
}
}
上一篇:解题:HNOI 2008 玩具装箱


下一篇:获取搜索结果的真实URL、描述、标题