2017.10.7 弹飞绵羊 思考记录

来源:互联网 发布:口琴的选择 知乎 编辑:程序博客网 时间:2024/05/16 09:56

。。这个题根据弹后的关系是很容易想出一个森林的。。修改连接关系就是cut和link。。

但是分块的做法似乎十分优越,,好写好调。所以学一下分块的写法

首先每一个区间的信息都是可以做到O(1)查询的。。就是dfs预处理

但如果有修改,就需要更新dfs,是O(n)的

由于每个点只会往后走,所以可以把原森林划分为从后往前的若干段

这样我们可以用类似dfs的便利对每个块处理处答案,使查询每个块为O(1)

这时要保留每个点到下一个块的哪个点的信息即可

修改一个块对其他块不造成影响,因为答案是分段统计的。


均摊o(n*sqrt(n)),但实际跑的很快


码:

#include<iostream>#include<cstdio>#include<cmath>using namespace std;#define N 300005int n,i,l[N],r[N],kuai[N],a[N],m,j,ans,o,oo,hou[N],len[N],q,op;int main(){scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d",&a[i]);}m=sqrt(n);for(i=1;i<=m;i++){l[i]=r[i-1]+1;for(j=l[i];j<=l[i]+m;j++)kuai[j]=i;r[i]=l[i]+m;}r[m]=n;for(i=n;i>=1;i--){ o=i+a[i];if(o>n){hou[i]=0;len[i]=1;continue;}if(o>r[kuai[i]]){hou[i]=o; len[i]=1; continue;}hou[i]=hou[o]; len[i]=len[o]+1;}scanf("%d",&q);while(q--){scanf("%d",&op);if(op==1){ans=0;scanf("%d",&o);o++;while(o){ans+=len[o];o=hou[o];}printf("%d\n",ans);}else{scanf("%d%d",&o,&oo);o++;a[o]=oo;op=o;for(i=r[kuai[op]];i>=l[kuai[op]];i--){o=i+a[i];if(o>n){hou[i]=0;len[i]=1;continue;}if(o>r[kuai[i]]){hou[i]=o; len[i]=1; continue;}hou[i]=hou[o]; len[i]=len[o]+1;}}}}



原创粉丝点击