1. 程式人生 > >計蒜客16492 building(二分線段樹/分塊)

計蒜客16492 building(二分線段樹/分塊)

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;
int
B[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(二分線段樹/分塊)