HNOI2010 弹飞绵羊
这道题听说是LCT的裸题……但是我只会分块。
分块的复杂度肯定是能过的orz,抗下200000很有信心。
我们还是老套路分成sqrt(n)块,之后我们统计两个值,一个是当前点弹几次会被弹出块,第二个是当前点弹出块以后到了哪(这两个都是要倒着枚举的,O(n))
之后,对于查询,我们直接暴力跳就行了,复杂度为O(sqrt(n)),而对于修改的话,修改一个块内的某一个值对前后块都没有任何影响,只要暴力把这个块内所有值全部重构即可,复杂度为O(sqrt(n)),总复杂度为O(nsqrt(n))。
简直是暴力到极限了……反正我真的是被刷新了三观orz。
代码也很简洁,看一下代码。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> #include<cstring> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar('\n') #define pr pair<int,int> #define mp make_pair #define fi first #define sc second using namespace std; typedef long long ll; const int M = 200005; const int N = 10000005; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >='0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } int n,m,B,cnt,ans,a[M],l[M],r[M],step[M],to[M],blo[M],g = 1,op,x,y; int main() { n = read(); rep(i,1,n) a[i] = read(); B = (int)sqrt(n),cnt = (n % B) ? n / B + 1 : n / B; rep(i,1,cnt) l[i] = r[i-1] + 1,r[i] = l[i] + B - 1;r[cnt] = n; rep(i,1,n) { blo[i] = g; if(i == r[g]) g++; if(g > cnt) break; } //rep(i,1,n) printf("#%d ",blo[i]);enter; per(i,n,1) { to[i] = i + a[i]; if(to[i] > r[blo[i]]) step[i] = 1; else step[i] = step[to[i]] + 1,to[i] = to[to[i]]; } m = read(); while(m--) { op = read(); if(op == 1) { x = read() + 1; int ans = 0; while(x <= n) ans += step[x],x = to[x]; printf("%d\n",ans); } else { x = read() + 1,y = read(),a[x] = y; per(i,r[blo[x]],l[blo[x]]) { to[i] = i + a[i]; if(to[i] > r[blo[i]]) step[i] = 1; else step[i] = step[to[i]] + 1,to[i] = to[to[i]]; } } //rep(i,1,n) printf("%d ",step[i]);enter; //rep(i,1,n) printf("%d ",to[i]);enter; } return 0; }
当你意识到,每个上一秒都成为永恒。