关于此题[ABC379F] Buildings 2 单调栈加线段树二分的一些总结

传送门

  • 题目大意:给定一个序列h表示房屋高度,规定当(i,j)满足hihj之间没有比hj高的房屋时,在i房屋可以看见j房屋。现给定q个询问li,ri,问ri后的同时能被liri看见的房屋有多少

  • 首先我们可以预处理出在每个房屋往右能看见多少房屋,这可以用单调栈实现。问题是如何回答询问。我们发现,如果想让liri都能看见某一个ri右的房屋,那么这个房屋一定要比(li,ri]区间中的房屋最高的还要高。于是我们只需要维护一下(li,ri]区间的最大值,然后在ri往右的所有房屋中,找到第一个比这个最大值大的房屋高度即可,那么这个房屋的上一个房屋所预处理出的答案就是询问的答案。然而房屋的高度不是有序的,所以不能直接用二分求出第一个比该最大值大的房屋高度,我们可以用线段树二分来实现这个过程。用线段树维护区间最大值,当我们处在当前区间时,如果左儿子区间的最大值比询问的值大,那么就往左边找,不然就往右,如果左右两边的最大值都比查询的小,说明没有符合要求的。然而左儿子区间可能不完全在限制区间中,所以即使左儿子区间最大值比询问的值大也可能查询不到结果(可能最大值在限制区间的外面),此时也得查右区间。

#include<bits/stdc++.h>
    
using namespace std;
    
long long t;
const long long N = 5e5 + 10;
long long n,q;
long long h[N],tr[N],num[N],tmp[N],top;
long long maxn[N * 4];

void build(long long k,long long l,long long r) {
    if(l == r) {
        maxn[k] = h[l];
        return;
    }
    long long mid = (l + r) >> 1;
    build(k * 2,l,mid);
    build(k * 2 + 1,mid + 1,r);
    maxn[k] = max(maxn[k * 2],maxn[k * 2 + 1]);
}

long long _query(long long k,long long l,long long r,long long x,long long y,long long v) {
    if(l == r) return l;
    long long mid = (l + r) >> 1;
    long long res = n + 1;
    if(mid >= x && maxn[k * 2] > v) res = min(res,_query(k * 2,l,mid,x,y,v));
    if(res != n + 1) return res;
    if(mid < y && maxn[k * 2 + 1] > v) res = min(res,_query(k * 2 + 1,mid + 1,r,x,y,v));
    return res;
}

long long lowbit(long long x) {
    return x & (-x);
}

void add(long long lo,long long v) {
    for(;lo <= n;lo += lowbit(lo))
        tr[lo] = max(tr[lo],v);
}

long long query(long long l,long long r) {
    long long res = 0;
    while(l <= r) {
        if(r - lowbit(r) >= l) {
            res = max(res,tr[r]);
            r -= lowbit(r);
        }
        else {
            res = max(res,h[r]);
            r--;
        }
    }
    return res;
}
    
void solve() {
    cin >> n >> q;
    for(long long i = 1;i <= n;i++) cin >> h[i],add(i,h[i]);
    build(1,1,n);
    for(long long i = n;i >= 1;i--) {
        num[i] = top;
        while(top && tmp[top] < h[i]) top--;
        tmp[++top] = h[i];
    }
    for(long long i = 1,l,r;i <= q;i++) {
        cin >> l >> r;
        long long maxn = query(l + 1,r);
        long long key = _query(1,1,n,r + 1,n,maxn);
        if(key == n + 1) cout << 0 << '\n';
        else cout << num[key - 1] << '\n';
    }
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    t = 1;
    while(t--) solve();
    
    return 0;
}
posted @   孤枕  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
这个世界早已无法拯救,可我们还必须成为英雄。