[HNOI2010] 弹飞绵羊 bounce
标签:分块。
题解:
200000,而且标号从0开始,很符合分块的条件啊。看看怎么实现。
首先分成√n个区间,然后如果我们对于每一个位置i,求出一个Next[i]和step[i],分别表示跳到的后一个位置与步数,因为是分块所以就是跳到下一个区间的步数与位置了。处理这两个数组要从前到后,只需要O(n)。
然后查询:自然是使用这两个数组,跳出去就return,复杂度O(√n)。
修改:修改一个点自然是O(1),但是前面的会跳到这个地方,那不是前面的都要改?非也,因为Next[]仅仅跨越了一个区间,所有最多有这个区间的起始位置到i个是需要更改的,也就是最大√n个,我们从i到起始位置烦着枚举,复杂度O(√n)。
所以总的复杂度为O(m√n)。
1 #include<cmath> 2 #include<cstdio> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 const int MAXN=210000; 7 int n,m,cnt; 8 int W[MAXN],Next[MAXN],step[MAXN],team[MAXN]; 9 inline int gi(){int res; scanf("%d",&res); return res;} 10 void update(int p) 11 { 12 if(p+W[p]>=n) 13 { 14 step[p]=1; 15 Next[p]=n; 16 return ; 17 } 18 int net=p+W[p]; 19 if(team[p]==team[net]) 20 { 21 step[p]=step[net]+1; 22 Next[p]=Next[net]; 23 } 24 else 25 { 26 step[p]=1; 27 Next[p]=net; 28 } 29 } 30 int query(int p) 31 { 32 int res=0; 33 while(p!=n) 34 { 35 res+=step[p]; 36 p=Next[p]; 37 } 38 return res; 39 } 40 int main() 41 { 42 n=gi(); cnt=sqrt(n); 43 for(int i=0;i<n;i++) W[i]=gi(); 44 for(int i=0;i<n;i++) team[i]=i/cnt; 45 for(int i=n-1;i>=0;i--) update(i); 46 m=gi(); 47 while(m--) 48 { 49 int op=gi(),p=gi(); 50 if(op==2) 51 { 52 int w=gi(); 53 W[p]=w; 54 for(int i=p;i>=0;i--) 55 if(team[p]==team[i]) 56 update(i); 57 else 58 break; 59 } 60 else 61 printf("%d\n",query(p)); 62 } 63 return 0; 64 }
标签:LCT
题解:
此题当然不缺乏LCT做法,对于LCT来说,这道题就是一道模板题,每次修改cut再link,维护sz代表子树的大小。使用一个根节点:n+1,也就是跳出去。M+A+S,查询x的左子树大小即可,也就是比他深度小的点的个数,不就是多少步跳出去吗?
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 using namespace std; 5 const int MAXN=300099; 6 int n,m; 7 int fa[MAXN],rev[MAXN],val[MAXN],Q[MAXN],ch[MAXN][2],sz[MAXN]; 8 bool isroot(int x){ return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; } 9 void Update(int x){ sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1; } 10 bool get(int x){ return ch[fa[x]][1]==x ;} 11 void Down(int x){ if(rev[x]){ rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; rev[x]^=1; swap(ch[x][0],ch[x][1]); } } 12 void Rotate(int x) 13 { 14 int old=fa[x],oldf=fa[old],op=get(x); 15 if(!isroot(old)) ch[oldf][ch[oldf][1]==old]=x; 16 ch[old][op]=ch[x][op^1]; fa[ch[x][op^1]]=old; 17 ch[x][op^1]=old; fa[old]=x; fa[x]=oldf; 18 Update(old); Update(x); 19 } 20 void Splay(int x) 21 { 22 int tp=1; Q[1]=x; 23 for(int i=x;!isroot(i);i=fa[i]) Q[++tp]=fa[i]; 24 for(int i=tp;i;i--) Down(Q[i]); 25 for(int FA; !isroot(x) ; Rotate(x)) 26 { 27 FA=fa[x]; 28 if(!isroot(FA)) Rotate(get(x)==get(FA)?FA:x); 29 } 30 } 31 void Access(int x){ int t=0; while(x){ Splay(x); ch[x][1]=t; Update(x); t=x; x=fa[x]; } } 32 void Makeroot(int x){ Access(x); Splay(x); rev[x]^=1;} 33 void Link(int x,int y){ Makeroot(x); fa[x]=y;} 34 void Cut(int x,int y){ Makeroot(x); Access(y); Splay(y); if(ch[y][0]==x) fa[x]=ch[y][0]=0;} 35 int main( ) 36 { 37 scanf("%d",&n); sz[n+1]=1; 38 for(int i=1;i<=n;i++) scanf("%d",&val[i]) , sz[i]=1; 39 for(int i=n;i>=1;i--) Link(i,min(i+val[i],n+1)); 40 scanf("%d",&m); 41 while(m--) 42 { 43 int x,op,y,ans=0; 44 scanf("%d%d",&op,&x); x++; 45 if(op==1) 46 { 47 Makeroot(n+1); Access(x); Splay(x); 48 printf("%d\n",sz[ch[x][0]]); 49 } 50 else 51 { 52 scanf("%d",&y); 53 Makeroot(n+1); Access(x); 54 Cut(x,min(x+val[x],n+1)); 55 val[x]=y; 56 Link(x,min(x+val[x],n+1)); 57 } 58 } 59 return 0; 60 }