线段树的一些用法

1.单调栈,存储前缀最大值

链接 洛谷:楼房重建

要求区间修改,线段树

关于如何 pushup 节点

父节点的 num = 左子节点的num + query(右子节点中大于左子节点的最大值的点的数目)

query中

如果当前区间的最大值已经小于等于所给标准 g ,返回0

如果l == r, 直接返回 a[l] > g

否则:

1.若当前节点的左子节点的 maxn 小于等于 g,则查询右区间

2. 否则,返回 query(左区间) + 该区间的 num - 左区间的 num(原因: 如果左区间的最大值已经大于 g,那么整个区间的最大值也一定大于 g,那么右区间中大于 g,且严格单增的节点数一定是 总区间的 num - 左区间的 num)

#include<bits/stdc++.h>

const int MAXN = 1e5 + 10;
using namespace std;

struct node{
    int l, r;
    double maxn;
    double minn;
    int num;
}t[MAXN << 2];

int tot;
int ro;
int n, m;
double a[MAXN];
int poi, x;

int query(int rt, int l, int r, double g)
{
    if(t[rt].maxn <= g) return 0;
    int mid = l + r >> 1;
    if(l == r) return a[l] > g;
    if(t[t[rt].l].maxn <= g) return query(t[rt].r, mid + 1, r, g);
    else return query(t[rt].l, l, mid, g) + t[rt].num - t[t[rt].l].num;
}

void update(int &rt, int l, int r, int poi, int x)
{
    if(!rt) rt = ++tot;
    if(l == r)
    {
        if(l == poi) t[rt].maxn = t[rt].minn = (double)x / poi;
        t[rt].num = 1;
        return;
    }
    int mid = l + r >> 1;
    if(poi <= mid) update(t[rt].l, l, mid, poi, x);
    else update(t[rt].r, mid + 1, r, poi, x);
    t[rt].maxn = max(t[t[rt].l].maxn, t[t[rt].r].maxn);
    t[rt].num = t[t[rt].l].num + query(t[rt].r, mid + 1, r, t[t[rt].l].maxn);    
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin>> n >> m;
    for(int i = 1;i <= m;i++) 
    {
        cin>> poi >> x;
        a[poi] = (double)x / poi;
        update(ro, 1, n, poi, x);
        cout << t[1].num << '\n';
    }
    return 0;
}
View Code

 

posted @ 2024-01-21 17:28  是谁不可理喻  阅读(22)  评论(0)    收藏  举报