zoukankan      html  css  js  c++  java
  • luogu2161 [SHOI2009]会场预约

    题目大意

      随着时间的推移这里有几个任务对应着一段区间。每次要将任务安到时间线上时,要把时间线上已有的与该任务对应区间有交集的区间对应的任务删去。求每次删去的区间个数,以及整个时间线上有几个任务。时间线长度m<=100000,任务个数n<=200000

    题解

      对于一个新加入的区间,我们要从右往左枚举每一个左端点小于等于新区间右端点的任务,直到枚举到了一个任务其右端点小于新任务的左端点。对于每一个要枚举到的任务,我们要尽可能缩小找到它的时间复杂度。于是建立一个权值树状数组,key值时间,值是左端点位于该点的任务个数。其维护的就是左端点个数的前缀和了,它满足单调性。左端点所在的地方就是权值增加的地方,而对于一个新区间,新区间右端点所在的权值前缀和就是离该点左侧的第一个左端点所在位置的权值前缀和。于是我们可以轻松用LowerBound得到区间,就这样不断删除二分删除二分(我们对于每一个左端点整一个数组维护其对应的右端点),直到有一个区间右端点小于新区间左端点为止。极端复杂度$O(n^2 log m)$。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX_LEN = 100010, TotLen = 100000;
    int LmatchR[MAX_LEN];
    
    struct BST
    {
    private:
        int C[MAX_LEN];
        int N;
    
        int Lowbit(int x)
        {
            return x & -x;
        }
    
    public:
        BST(int n):N(n){}
    
        int Query(int p)
        {
            int ans = 0;
            while (p > 0)
            {
                ans += C[p];
                p -= Lowbit(p);
            }
            return ans;
        }
    
        void Update(int p, int delta)
        {
            while (p <= N)
            {
                C[p] += delta;
                p += Lowbit(p);
            }
        }
    }g(TotLen);
    
    int PrefixFind;
    
    bool GtPrefixFind(int k)
    {
        return g.Query(k) >= PrefixFind;
    }
    
    int LowerBound(int l, int r, bool(*InRange)(int))
    {
        if (!InRange(r))
            return -1;
        while (l < r)
        {
            int mid = (l + r) / 2;
            if (InRange(mid))
                r = mid;
            else
                l = mid + 1;
        }
        return l;
    }
    
    int main()
    {
        int qCnt;
        scanf("%d", &qCnt);
        while (qCnt--)
        {
            char op;
            int newL, newR, curL, delCnt;
            scanf("
    %c", &op);
            switch (op)
            {
            case 'A':
                scanf("%d%d", &newL, &newR);
                delCnt = 0;
                while (true)
                {
                    PrefixFind = g.Query(newR);
                    if (PrefixFind == 0)
                        break;
                    curL = LowerBound(1, newR, GtPrefixFind);
                    if (curL == -1)
                        break;
                    if (LmatchR[curL] >= newL)
                    {
                        delCnt++;
                        g.Update(curL, -1);
                    }
                    else
                        break;
                }
                g.Update(newL, 1);
                LmatchR[newL] = newR;
                printf("%d
    ", delCnt);
                break;
            case 'B':
                printf("%d
    ", g.Query(TotLen));
                break;
            }
        }
    }
    

      

  • 相关阅读:
    springboot中多端口启动(这里也适用于https既443端口)
    Gson的fromJson()方法(从Json相关对象到Java实体或转换成List集合)
    [C++] STL源码中学到的 Traits 编程技法的应用
    【解决问题】UNIAPP、VUE 中DATA 数组更新后页面不同步动态渲染更新
    selenium操作chrome时的一些配置
    在react项目中使用fetch 和 JWT进行权限验证(转)
    滚动条的设置(样式包括宽度,颜色等)zhuan
    css3 box-shadow阴影(外阴影与外发光)图示讲解(zhuan)
    js 截断字符串 超过几个字加...
    create-react-app 打包部署
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9474322.html
Copyright © 2011-2022 走看看