bzoj2002 [Hnoi2010]Bounce 弹飞绵羊——分块
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2002
第一次用分块,感觉超方便啊;
如果记录每个点的弹力系数,那么是O(1)修改O(n)查询;
如果记录每个点几次被弹飞,那么是O(n)修改O(1)查询;
那么如果分成根号n块,则相当于每块都路径压缩,修改和查询都是根号n的复杂度!
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; int const maxn=200005; int n,m,k[maxn],nxt[maxn],t[maxn],bh[maxn],K; void change(int x) { // int s=0,nw=x; // while(bh[nw]==bh[x]&&nw<=n)s++,nw+=k[nw]; // t[x]=s;nxt[x]=nw; int y=x+k[x]; if(bh[y]!=bh[x])t[x]=1,nxt[x]=y; else t[x]=t[y]+1,nxt[x]=nxt[y]; } int query(int x) { // if(x>n)return 0; // int ret=t[x]; // ret+=query(nxt[x]); // return ret; int ret=0; while(x<=n)ret+=t[x],x=nxt[x]; return ret; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&k[i]); K=sqrt(n); for(int i=n;i;i--) { // if(i>tot*K)tot++;bh[i]=tot; bh[i]=(i-1)/K+1; // int j=i,s=0; // while(bh[j]==bh[i]&&j<=n)j+=k[j],s++; // t[i]=s;nxt[i]=j; int j=i+k[i]; if(bh[j]!=bh[i])t[i]=1,nxt[i]=j; else t[i]=t[j]+1,nxt[i]=nxt[j]; } scanf("%d",&m); int x,y,z; while(m--) { scanf("%d%d",&x,&y);y++; if(x==1)printf("%d\n",query(y)); else { scanf("%d",&z); k[y]=z; // for(int i=(bh[y]-1)*K+1;i<=y;i++)change(i); for(int i=y;i>(bh[y]-1)*K;i--)change(i); } } return 0; }