[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 }
posted @ 2017-12-05 13:17  D_O_Time  阅读(180)  评论(0编辑  收藏  举报