bzoj2002 弹飞绵羊 分块orLCT

来源:互联网 发布:ios 10.0越狱工具 mac 编辑:程序博客网 时间:2024/05/22 03:53

       先简单讲一下LCT做法,每个点以它的到达点为父节点(没有到达点就连向根),结果就是深度。然后修改就是改变父亲,一个cut再一个link就好了。

       然后是分块。每个点维护它到达它所在块外面的点,及步数,预处理O(N)。查询时O(N/m)。修改时只需要修改x所在块在x前面的那些点即可,时间O(m)。因此总时间复杂度O(M*(N/m+m)+N)=O(MN^0.5+N)(取m=N^0.5)

AC代码如下:

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#define N 200005using namespace std;int n,m,a[N],nxt[N],len[N],blg[N],l[5005],r[5005];int read(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }return x;}int main(){n=read(); m=(int)sqrt(n); int i,j;for (i=1; i<=n; i++) a[i]=read();for (i=1; i<=m; i++){l[i]=r[i-1]+1; r[i]=r[i-1]+m;}r[m]=n;for (i=1; i<=m; i++)for (j=l[i]; j<=r[i]; j++) blg[j]=i;for (i=n; i; i--){int x=i+a[i];if (x>n){ nxt[i]=0; len[i]=1; }else if (x>r[blg[i]]){ nxt[i]=x; len[i]=1; }else{ nxt[i]=nxt[x]; len[i]=len[x]+1; }}int cas=read();while (cas--){int k=read(),x=read()+1;if (k==1){int ans=0; for (i=x; i; i=nxt[i]) ans+=len[i];printf("%d\n",ans);} else{int y=read(),t=blg[x]; a[x]=y;for (i=x; i>=l[t]; i--){int tmp=i+a[i];if (tmp>n){ nxt[i]=0; len[i]=1; }else if (tmp>r[t]){ nxt[i]=tmp; len[i]=1; }else{ nxt[i]=nxt[tmp]; len[i]=len[tmp]+1; }}}}return 0;}

by lych
2016.2.23

1 0