計蒜客16492 building(二分線段樹/分塊)
阿新 • • 發佈:2017-08-16
sin cst include sqrt ++ building scanf mat math
題解:
考慮用線段樹維護樓的最大值,然後這個問題就很簡單了。
每次可以向左二分出比x高的第一個樓a,同理也可以向右二分出另一個樓b,如果a,b都存在,答案就是b-a-1。
註意到二分是可以直接在線段樹上進行的,所以復雜度是O(nlogn)。
當然這裏是用分塊做的,更暴力一些。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int maxn = 1e5 + 100, maxN = 500; intB[maxN], Tag[maxN]; int a[maxn]; int n, m, N, L; void Update(int i){ if(Tag[i] == -1) return; int bl = i*L, br = min(n, (i+1)*L-1); for(int j = bl; j <= br; j++) a[j] = Tag[i]; Tag[i] = -1; } void Change(int l, int r, int v){ for(int i = 0; i < N; i++){ int bl = i*L, br = min(n, (i+1)*L-1); if(l <= bl && br <= r){ Tag[i] = v; B[i] = v; } else if(bl <= l && l <= br && bl <= r && r <= br){ Update(i); B[i] = max(B[i], v); for(int j = l; j <= r; j++) a[j] = v; }else if(bl <= l && l <= br){ Update(i); B[i] = max(B[i], v); for(int j = l; j <= br; j++) a[j] = v; } else if(bl <= r && r <= br){ Update(i); B[i] = max(B[i], v); for(int j = bl; j <= r; j++) a[j] = v; } } } int Findl(int x){ int bi = x/L; int bl = bi*L, br = min(n, (bi+1)*L-1); Update(bi); for(int i = x-1; i >= bl; i--){ if(a[i] > a[x]) return i; } for(int i = bi-1; i >= 0; i--){ if(B[i] > a[x]){ bl = i*L, br = min(n, (i+1)*L-1); Update(i); for(int j = br; j >= bl; j--) if(a[j] > a[x]) return j; } } return -1; } int Findr(int x){ int bi = x/L; int bl = bi*L, br = min(n, (bi+1)*L-1); Update(bi); for(int i = x+1; i <= br; i++){ if(a[i] > a[x]) return i; } for(int i = bi+1; i < N; i++){ if(B[i] > a[x]){ bl = i*L, br = min(n, (i+1)*L-1); Update(i); for(int j = bl; j <= br; j++) if(a[j] > a[x]) return j; } } return -1; } int main() { int x, y, z; cin>>n; for(int i = 1; i <= n; i++){ scanf("%d", &a[i]); } L = sqrt(n+0.5); N = n/L + 1; for(int i = 0; i < N; i++) Tag[i] = -1; for(int i = 1; i <= n; i++){ B[i/L] = max(B[i/L], a[i]); } cin>>m; for(int i = 1; i <= m; i++){ scanf("%d", &x); if(x == 1){ scanf("%d %d %d", &x, &y, &z); Change(x, y, z); } else { scanf("%d", &x); int l = Findl(x), r = Findr(x); if(l == -1 || r == -1) printf("-1\n"); else printf("%d\n", r-l-1); } } }
計蒜客16492 building(二分線段樹/分塊)