bzoj2002: [Hnoi2010]Bounce 弹飞绵羊 分块
这个题体现了分块不只是最大值最小值众数次数,而是一种清真的思想。
我们把整个序列分块,在每个块里处理每个位置跳出这个块的次数和跳出的位置,那么每次修改n0.5,每次查询也是,那么O(m* n0.5)的复杂度是可以的.
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #define MAXN 200010 #define s second #define f first using namespace std; inline int read() { int s=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9') { s=(s<<3)+(s<<1)+ch-48; ch=getchar(); } return s; } typedef pair<int,int> P; int k[MAXN]; P a[MAXN]; int pos[MAXN]; int lon,t; int n,m; inline int Min(int x,int y) { return x<y?x:y; } inline void do_it(int x) { int l=(x-1)*lon+1,r=x*lon; r=Min(r,n); for(int i=r;i>=l;i--) if(i+k[i]>r) { a[i].f=1; a[i].s=i+k[i]-r; } else { a[i].f=a[i+k[i]].f+1; a[i].s=a[i+k[i]].s; } } int main() { //freopen("bzoj_2002.in","r",stdin); //freopen("bzoj_2002.out","w",stdout); n=read(); lon=(int)sqrt(n+0.5); for(int i=1;i<=n;i++) k[i]=read(),pos[i]=(i-1)/lon+1; t=pos[n]; for(int i=1;i<=t;i++)do_it(i); m=read(); for(int i=1;i<=m;i++) { int opt=read(),x=read(); x++; if(opt==1) { int ans=0; while(x<=n) { ans+=a[x].f; x=pos[x]*lon+a[x].s; } printf("%d\n",ans); } else { int y=read(); k[x]=y; do_it(pos[x]); } } return 0; }
苟利国家生死以, 岂因祸福避趋之。