给定 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&∑)
{
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;
}