Codeforces Gym 100231B Intervals 线段树+二分+贪心

Intervals

题目连接:

http://codeforces.com/gym/100231/attachments

Description

给你n个区间,告诉你每个区间内都有ci个数

然后你需要找一个最小的点集,使得满足这n个区间的条件

Input

n

然后li,ri,ci

Output

输出最小点集大小

Sample Input

5

3 7 3

8 10 3

6 8 1

1 3 1

10 11 1

Sample Output

6

Hint

题意

题解:

线段树+二分+贪心

首先我们贪心一发,按照右端点排序之后,我们点肯定是优先放在右边

那么我们怎么确认有多少个放右边呢?

二分+线段树就好了,我们二分有多少个点放在右边,然后在用线段树的区间和来check是否大于ci就好了

代码

#include<bits/stdc++.h>
using namespace std;

#include<bits/stdc++.h>
using namespace std;

typedef int SgTreeDataType;
struct treenode
{
  int L , R  ;
  SgTreeDataType sum , lazy;
  void updata(SgTreeDataType v)
  {
      sum = (R-L+1)*v;
    lazy = v;
  }
};

treenode tree[301500];

inline void push_down(int o)
{
    SgTreeDataType lazyval = tree[o].lazy;
    if(lazyval!=0){
    tree[2*o].updata(lazyval) ; tree[2*o+1].updata(lazyval);
    tree[o].lazy = 0;
    }
}

inline void push_up(int o)
{
    tree[o].sum = tree[2*o].sum + tree[2*o+1].sum;
}

inline void build_tree(int L , int R , int o)
{
    tree[o].L = L , tree[o].R = R,tree[o].sum = tree[o].lazy = 0;
    if (R > L)
    {
        int mid = (L+R) >> 1;
        build_tree(L,mid,o*2);
        build_tree(mid+1,R,o*2+1);
    }
}

inline void updata(int QL,int QR,SgTreeDataType v,int o)
{
    if(QL>QR)return;
    int L = tree[o].L , R = tree[o].R;
    if (QL <= L && R <= QR) tree[o].updata(v);
    else
    {
        push_down(o);
        int mid = (L+R)>>1;
        if (QL <= mid) updata(QL,QR,v,o*2);
        if (QR >  mid) updata(QL,QR,v,o*2+1);
        push_up(o);
    }
}

inline SgTreeDataType query(int QL,int QR,int o)
{
    if(QL>QR)return 0;
    int L = tree[o].L , R = tree[o].R;
    if (QL <= L && R <= QR) return tree[o].sum;
    else
    {
        push_down(o);
        int mid = (L+R)>>1;
        SgTreeDataType res = 0;
        if (QL <= mid) res += query(QL,QR,2*o);
        if (QR > mid) res += query(QL,QR,2*o+1);
        push_up(o);
        return res;
    }
}

struct node
{
    int l,r,c;
}p[52000];
bool cmp(node a,node b)
{
    if(a.r==b.r&&a.l==b.l)
        return a.c<b.c;
    if(a.r==b.r)
        return a.l>b.l;
    return a.r<b.r;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d%d",&p[i].l,&p[i].r,&p[i].c);
        p[i].l+=1,p[i].r+=1;
    }
    sort(p+1,p+1+n,cmp);
    build_tree(1,p[n].r+100,1);
    int ans = 0;
    for(int i=1;i<=n;i++)
    {
        //int now = query(p[i].l,p[i].r,1);
        //if(now<p[i].c)
        //{
        int L = p[i].l-1,R = p[i].r;
        while(L<=R)
        {
            int mid = (L+R)/2;
            if(query(p[i].l,mid,1)+(p[i].r-mid)>=p[i].c)
                L=mid+1;
            else
                R=mid-1;
        }
        ans+=(p[i].r-L+1)-query(L,p[i].r,1);
        //cout<<L<<" "<<p[i].r<<endl;
        updata(L,p[i].r,1,1);
        //}
    }
    //for(int i=1;i<=p[n].r;i++)
    //    cout<<query(i,i,1)<<" ";
    //cout<<endl;
    cout<<ans<<endl;
}
/*
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值