zoukankan      html  css  js  c++  java
  • POJ 1201 Intervals

    传送门

    听说正常写法是差分约束?

    我怎么看都是贪心啊,所以就用贪心写了(其实是我忘记差分约束怎么写了)

    考虑把区间按右端点排序,那么对于每个区间,我们考虑选择的数尽量贴着区间右边,因为这样还可以尽量满足之后区间的要求

    (显然填在左边对后面没有任何好处,填右边一定比填左边好)

    然后这样搞如果直接暴力复杂度是可以卡到 $n^2$ 的,所以考虑用线段树优化一下这个贪心

    线段树维护一下当前每个位置是否已经选择,然后对于每个题目限制的区间 $l,r,x$,(区间 $[l,r]$ 内要选择 $x$ 个数)

    我们首先把 $x$ 先减去当前 $[l,r]$ 内已经选择的位置数量,然后现在问题就是确定位置 $p$ ,使得把当前 $[p,r]$ 内没有选择的数选择以后恰好满足限制

    这个东西显然是可以二分的,然后就做完了,复杂度因为二分时要线段树查询一下所以是 $n log ^2 max(r) $ 的,已经可以过了

    但是我脑子转不过来就是要写线段树上二分

    但是正常的线段树上二分是在整颗线段树 $[1,max(r)]$ 上二分,不慌,注意到此时 $(r,max(r)]$ 的所有位置都还没选

    所以把原本二分要求的值加上 $max(r)-r$ 即可在整颗线段树上二分了,复杂度 $n log max(r)$

    (如果实在听不懂的话直接看代码或许比较简单?)

    线段树维护区间赋值为 $1$ 时因为每个线段树节点最多被改变一次所以甚至不用打标记,直接暴力修改即可

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=1e5+7;
    int n,m,ans;
    struct dat {
        int l,r,mi;
        dat (int _l=0,int _r=0,int _mi=0) { l=_l,r=_r,mi=_mi; }
        inline bool operator < (const dat &tmp) const {
            return r!=tmp.r ? r<tmp.r : l<tmp.l;
        }
    }D[N];
    struct SegTree {
        int T[N<<2];
        void change(int o,int l,int r,int ql,int qr)
        {
            if(l>qr||r<ql||T[o]==r-l+1) return;
            if(l==r) { T[o]=1; return; }
            int mid=l+r>>1; change(o<<1,l,mid,ql,qr); change(o<<1|1,mid+1,r,ql,qr);
            T[o]=T[o<<1]+T[o<<1|1];
        }
        int query_sum(int o,int l,int r,int ql,int qr)
        {
            if(l>qr||r<ql) return 0;
            if(l>=ql&&r<=qr) return T[o];
            int mid=l+r>>1;
            return query_sum(o<<1,l,mid,ql,qr)+query_sum(o<<1|1,mid+1,r,ql,qr);
        }
        int query_pos(int o,int l,int r,int K)
        {
            if(l==r) return l;
            int mid=l+r>>1,val=r-mid-T[o<<1|1];
            if(K>val) return query_pos(o<<1,l,mid,K-val);
            return query_pos(o<<1|1,mid+1,r,K);
        }
    }T;
    int main()
    {
        n=read(); int a,b,c;
        for(int i=1;i<=n;i++)
        {
            a=read(),b=read(),c=read();
            m=max(m,b); D[i]=dat(a,b,c);
        }
        sort(D+1,D+n+1);
        for(int i=1;i<=n;i++)
        {
            int t=T.query_sum(1,1,m,D[i].l,D[i].r);
            if(t>=D[i].mi) continue;
            ans+=D[i].mi-t; int p=T.query_pos(1,1,m, D[i].mi-t + m-D[i].r);
            T.change(1,1,m,p,D[i].r);
        }
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    AE(ArcGIS Engine)的安装与配置(附加ArcGIS安装及所需安装包)
    C# 封装
    如何修改C# winform程序图标
    C#中ESRI.ArcGIS.esriSystem的引用问题
    c#窗体进度条
    【转】C#路径中获取文件全路径、目录、扩展名、文件名称
    【转】C# Application.DoEvent()的作用
    如何在Word中批量选中特定文本
    GIT
    git使用
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11719403.html
Copyright © 2011-2022 走看看