1. 程式人生 > >HNOI2010 彈飛綿羊

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; }