362. 区间

5 篇文章 0 订阅
5 篇文章 0 订阅

给定 n 个区间 [ai,bi] 和 n 个整数 ci。

你需要构造一个整数集合 Z,使得 ∀i∈[1,n],Z 中满足 ai≤x≤bi 的整数 x 不少于 ci 个。

求这样的整数集合 Z 最少包含多少个数。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含三个整数 ai,bi,ci。

输出格式

输出一个整数表示结果。

数据范围

1≤n≤50000,
0≤ai,bi≤50000,
1≤ci≤bi−ai+1

输入样例:

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

输出样例:

6

分析:树状数组+并查集+贪心

考虑把所有线段按照右端点 从小到大排序,依次考虑每一条线段的要求:如果已经满足要求则跳过,否则尽量选择靠后的数(贪心,因为之后的线段的右端点都在这条线段的右边,这样容错更高),因为Z是集合,所以每个数只能出现一次!!!

在查询一个区间的数时可以用树状数组,与此同时可以采用并查集来合并区间,避免不必要的访问。还有一个很重要的点,区间是有0的,此刻采用树状数组查询时会查到getsum(-1),因此我在写代码时就把所有区间都往后移动了一个;

代码如下:

#include <bits/stdc++.h>

using namespace std;

const int N=5e4+10;
struct node{
int l,r,c;
}a[N];
int tr[4*N],fa[N],d[N];
int n,ans;

bool cmp(node x,node y)
{
    return x.r<y.r;
}
int getsum(int x)
{
    int sum=0;
    x=max(0,x);
    for(int i=x;i;i-=i&(-i)) sum+=tr[i];
    return sum;
}
void add(int x)
{
    for(int i=x;i<4*N;i+=i&(-i)) tr[i]+=1;
}
int find(int x)
{
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
int main()
{
    cin>>n;
    for(int i=1;i<N;i++) fa[i]=i;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].l>>a[i].r>>a[i].c;
    }
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++)
    {
        int sum=getsum(a[i].r)-getsum(a[i].l-1);
        sum=a[i].c-sum;
        if(sum>0)
        {
            ans+=sum;
            for(int j=a[i].r;j>=a[i].l&&sum;)
            {
                if(!d[j])
                {
                    d[j]=1;
                    add(j);
                    sum--;
                    fa[j]=j-1;
                }
                if(find(j)==j) j--;
                else j=fa[j];
            }
            
        }
    }
    cout<<ans;
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值