[关键字]:块状链表
[题目大意]:有n个弹力装置,绵羊落在i个装置上会被向后弹到i+ki个装置上或被弹飞,问从i个装置开始要想被弹飞需要多少次,中间会改变装置的弹力系数。
//=============================================================================================
[分析]:做法有三种:动态树(不会)、伸展树+括号序列(不会+太麻烦)、块状链表。虽然块状链表在这里只是水过,但还是很好写和理解的。在以sqrt(n)分块后,对每个装置维护f[i].t[i],
f[i]表示从i开始要弹几次才能弹出该块,可以用递推来维护,t[i]表示i会弹到下一个块的哪个装置上。查找时只要沿着t[]数组找到头累加f[]值就行了。更改时因为只会往后弹,所以只要将与要修改装置在同一个块里且在他后面的装置的f[]\t[]再算一遍就行了。
[代码]:
View Code
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int MAXN=1000; int n,m,tot; int belong[MAXN],l[MAXN],f[MAXN],t[MAXN],k[MAXN]; void Init() { scanf("%d",&n); int m=(int)sqrt(n),j=m; //printf("%d\n",m); for (int i=0;i<n;++i) { scanf("%d",&k[i]); if (j==m) j=1,l[++tot]=i; else ++j; belong[i]=tot; } l[tot+1]=n; for (int i=n-1;i>=0;--i) if (i+k[i]>=l[belong[i]+1]) f[i]=1,t[i]=i+k[i]; else f[i]=f[i+k[i]]+1,t[i]=t[i+k[i]]; } int ask(int pos) { int sum=0; while (pos<n) {sum+=f[pos],pos=t[pos];} //printf("\n"); return sum; } void Change(int j,int k2) { k[j]=k2; for (int i=j;i>=l[belong[j]];--i) if (i+k[i]>=l[belong[i]+1]) f[i]=1,t[i]=i+k[i]; else f[i]=f[i+k[i]]+1,t[i]=t[i+k[i]]; } void Solve() { scanf("%d",&m); int flag,j,k2; while (m--) { scanf("%d",&flag); if (flag==1) { scanf("%d",&j); printf("%d\n",ask(j)); } if (flag==2) { scanf("%d%d",&j,&k2); Change(j,k2); } } } int main() { freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); Init(); /*for (int i=0;i<n;++i) printf("%d %d %d\n",belong[i],f[i],t[i]);*/ Solve(); fclose(stdin); fclose(stdout); return 0; }