当前位置: 代码迷 >> 综合 >> POJ - 1201 Intervals(贪心+数据结构)
  详细解决方案

POJ - 1201 Intervals(贪心+数据结构)

热度:14   发布时间:2023-11-25 07:29:58.0

POJ - 1201 Intervals(贪心+数据结构)

考虑把所有线段按照右端点 b b b 从小到大排序,依次考虑每一条线段的要求:

  • 如果已经满足要求则跳过
  • 否则尽量选择靠后的数(因为之后的线段的右端点都在这条线段的右边,这样容错更高)

所以,我们可以建一个数组, f [ i ] f[i] f[i] 表示 i i i 数字是否选择(填 1 1 1 0 0 0),扫一遍 [ l , r ] [l,r] [l,r] 区间求和,然后从后往前贪心放数即可。
对于每条线段需要 O ( r ? l + 1 ) O(r?l+1) O(r?l+1)。所以最坏情况下 O ( n 2 ) O(n^{2}) O(n2)

考虑用数据结构优化。

  • 询问 [ l , r ] [l,r] [l,r] 区间的数字个数
  • 将值为 x x x 的位置 + 1 +1 +1
  • 从后往前,找到比当前位置靠前的下一个 0 0 0 的位置。

这就是 “区间求和,单调修改”,典型的树状数组。 O ( n l o g 2 50000 ) O(nlog_250000) O(nlog2?50000)

#include<cstdio>
#include<algorithm>
using namespace std;
typedef pair<int,int> PII;
typedef pair<PII,int> PIII;
const int N = 50010;
PIII g[N];
int f[N],c[N];
inline bool cmp(const PIII &X,const PIII &Y)
{
    return X.first.second<Y.first.second;
}
inline int ask(int x)
{
    int res=0;for(;x>0;x-=(x&-x)) res+=c[x];return res; 
}
inline void add(int x,int y)
{
    for(;x<N;x+=(x&-x)) c[x]+=y;
}
int main()
{
    int n;scanf("%d",&n);for(int i=1;i<=n;i++){
    int a,b,c;scanf("%d%d%d",&a,&b,&c);g[i]=(PIII){
    (PII){
    a,b},c};}sort(g+1,g+n+1,cmp);int ans=0;for(int i=1;i<=n;i++){
    int l=g[i].first.first,r=g[i].first.second,cnt=g[i].second;cnt-=ask(r)-ask(l-1);if(cnt>0){
    for(int j=r;j>=l&&cnt;j--)if(!f[j]){
    f[j]=1;ans++;cnt--;add(j,1);}}}printf("%d\n",ans);
}
  相关解决方案