首页 > 代码库 > BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊

BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊

一眼题,LCT。

然后悲剧的发现不会写,只好分块来做。

令s = sqrt(n),那么先分成s块,每块s个弹簧。

现在让每个点记录两个值,cnt和to,分别表示弹到这个块外面的次数和弹到了哪里。

我们发现单点修改只要修改块内元素,时间复杂度是O(s)的;而单点查询要查他后面的所有块,时间复杂度也是O(s)的,

于是总的复杂度是O(Q * logn),解决!

 

 1 /************************************************************** 2     Problem: 2002 3     User: rausen 4     Language: C++ 5     Result: Accepted 6     Time:1736 ms 7     Memory:5700 kb 8 ****************************************************************/ 9  10 #include <cstdio>11 #include <cmath>12 #include <algorithm>13  14 using namespace std;15  16 int n, m, T, tot;17 int w[250000], cnt[250000], to[250000], block[250000], a[250000];18  19 void build(){20     int x = tot = 0, y;21     while (x < n){22         x += T, ++tot;23         w[tot] = x;24     }25     w[tot] = min(n, w[tot]);26      27     for (int i = tot; i >= 1; --i)28         for (int x = w[i]; x > w[i - 1]; --x){29             y = x + a[x];30             if (y <= w[i])31                 to[x] = to[y], cnt[x] = cnt[y] + 1;32             else to[x] = y, cnt[x] = 1;33             block[x] = i;34         }35 }36  37 int query(int x){38     int res = 0;39     while (x <= n)40         res += cnt[x], x = to[x];41     return res;42 }43  44 void change(int x){45     int B = block[x], y;46     for (int i = x; i > w[B - 1]; --i){47         y = i + a[i];48         if (y <= w[B])49             to[i] = to[y], cnt[i] = cnt[y] + 1;50         else to[i] = y, cnt[i] = 1;51     }52 }53  54 int main(){55     scanf("%d", &n);56     for (int i = 1; i <= n; ++i)57         scanf("%d", a + i);58     T = (int) sqrt(n);59     build();60  61     scanf("%d", &m);62     int X, Y, Z;63     while (m--){64         scanf("%d%d", &X, &Y);65         if (X == 1)66             printf("%d\n", query(Y + 1));67         else {68             scanf("%d", &Z);69             a[Y + 1] = Z;70             change(Y + 1);71         }72     }73     return 0;74 }
View Code

(p.s. 从0开始坑死人啊。。。。)

BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊