计蒜客16492 building(二分线段树/分块)
Posted Saurus
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计蒜客16492 building(二分线段树/分块)相关的知识,希望对你有一定的参考价值。
题解:
考虑用线段树维护楼的最大值,然后这个问题就很简单了。
每次可以向左二分出比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(二分线段树/分块)的主要内容,如果未能解决你的问题,请参考以下文章
计蒜客- Lpl and Energy-saving Lamps 线段树+点更新