• 【BZOJ2957】楼房重建(线段树)


    题目

    BZOJ2957

    分析

    题意:给定一个数列 (a),动态修改,求前缀最大值的数量。如果 (i) 满足 (max_{j=1}^{i-1}a_j<a_i) ,那么 (a_i) 是前缀最大值。(真的不是求最长上升子序列的长度!)

    考虑用线段树维护,在区间 ([l,r]) 上维护 ([l,r]) 的最大值和 子区间 ([l,r]) 中前缀最大值的数量(注意这里只考虑区间 ([l,r]) ,不考虑 ([1,l)) 对它的影响。以下称这个值为「答案」)。合并左右区间时,最大值可以直接合并,而答案的合并比较麻烦:

    答案并不是直接把两个子区间的答案相加。左区间的答案可以直接加进当前区间的答案。设左区间的最大值为 (x) ,那么右区间所有小于 (x) 的前缀最大值都不能算进答案。所以,右区间对当前区间答案的贡献是右区间中「所有大于 (x) 的前缀最大值的数量」。

    由于前缀最大值一定是单调递增的,所以「大于 (x) 的前缀最大值」一定是右区间中前缀最大值的一个后缀,可以通过类似于二分查找的方法解决。具体来说,从当前的右区间往下走,如果左边的最大值大于 (x) ,说明左边对 当前正在计算答案 的区间(不是当前走到的区间!)有贡献,则往左边搜,同时加上右边对当前走到的区间的贡献(不是右边的答案!);否则往右边搜。

    为了实现这一过程,每个非叶子区间还要记录右区间对该区间的答案的贡献,理论上要按照上面的做法算完记下来,但由于左区间的贡献就是左区间的答案,所以直接用当前区间答案减去左区间答案就是右区间的贡献。时间复杂度 (O(nlog^2n))

    代码

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    using namespace std;
     
    namespace zyt
    {
        template<typename T>
        inline bool read(T &x)
        {
            char c;
            bool f = false;
            x = 0;
            do
                c = getchar();
            while (c != EOF && c != '-' && !isdigit(c));
            if (c == EOF)
                return false;
            if (c == '-')
                f = true, c = getchar();
            do
                x = x * 10 + c - '0', c = getchar();
            while (isdigit(c));
            if (f)
                x = -x;
            return true;
        }
        template<typename T>
        inline void write(T x)
        {
            static char buf[20];
            char *pos = buf;
            if (x < 0)
                putchar('-'), x = -x;
            do
                *pos++ = x % 10 + '0';
            while (x /= 10);
            while (pos > buf)
                putchar(*--pos);
        }
        const int N = 1e5 + 10;
        namespace Segment_Tree
        {
            struct node
            {
                double mx;
                int ans;
            }tree[N << 2];
            int cal(const int rot, const int lt, const int rt, const double lim)
            {
                if (lt == rt)
                    return tree[rot].mx > lim ? 1 : 0;
                int mid = (lt + rt) >> 1;
                if (tree[rot << 1].mx < lim)
                    return cal(rot << 1 | 1, mid + 1, rt, lim);
                else
                    return tree[rot].ans - tree[rot << 1].ans + cal(rot << 1, lt, mid, lim);
            }
            void update(const int rot, const int lt, const int rt)
            {
                tree[rot].mx = max(tree[rot << 1].mx, tree[rot << 1 | 1].mx);
                int mid = (lt + rt) >> 1;
                tree[rot].ans = tree[rot << 1].ans + cal(rot << 1 | 1, mid + 1, rt, tree[rot << 1].mx);
            }
            void change(const int rot, const int lt, const int rt, const int pos, const double x)
            {
                if (lt == rt)
                    return void((tree[rot].mx = x, tree[rot].ans = (x > 0 ? 1 : 0)));
                int mid = (lt + rt) >> 1;
                if (pos <= mid)
                    change(rot << 1, lt, mid, pos, x);
                else
                    change(rot << 1 | 1, mid + 1, rt, pos, x);
                update(rot, lt, rt);
            }
            int query()
            {
                return tree[1].ans;
            }
        }
        int n, m;
        int work()
        {
            using Segment_Tree::change;
            using Segment_Tree::query;
            read(n), read(m);
            for (int i = 1; i <= n; i++)
                change(1, 1, n, i, 0);
            while (m--)
            {
                int x, y;
                read(x), read(y);
                change(1, 1, n, x, (double)y / x);
                write(query()), putchar('
    ');
            }
            return 0;
        }
    }
    int main()
    {
        return zyt::work();
    }
    
  • 相关阅读:
    linux驱动程序之电源管理之标准linux休眠与唤醒机制分析(一)
    linux驱动程序之电源管理 之linux休眠与唤醒(2)
    linux驱动程序之电源管理之regulator机制流程 (1)
    ARM--存储管理器
    元朝皇帝列表 元朝历代皇帝简介
    linux下valgrind的使用概述
    linux之sort用法
    python的ftplib模块
    Python使用struct处理二进制(pack和unpack用法)
    Python使用struct处理二进制(pack和unpack用法)
  • 原文地址:https://www.cnblogs.com/zyt1253679098/p/12222591.html
Copyright © 2020-2023  润新知