题意:
给n个线段,我们需要保证每个点(只考虑整数点)的重复不超过k次,让我们找出要剔除的线段,并输出这些线段的位置。
D1. Too Many Segments (easy version)
思路:
没有思路,要说思路就是暴力!(哈哈)真的是纯暴力
就是将一个线段分别以每个整数点为起点,右端点为终点,分为len个线段,都存起来。并且按照新的左端点升序,左端点相同线段长度降序排序。然后遍历一遍所有的线段,如果有不符合条件的就把这个子线段所在的原线段删掉【因为是按照长度降序排序的,所以贪心删掉最长的】。然后再存一下删掉线段的序号即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
using namespace std
;
typedef long long ll
;
typedef unsigned long long ull
;
const int maxN
= 2e5 + 5;
struct node
{
int l
, r
, len
, id
;
friend bool operator < (node n1
, node n2
)
{
if(n1
.l
== n2
.l
)
return n1
.len
> n2
.len
;
return n1
.l
< n2
.l
;
}
}info
[maxN
];
int num
[maxN
] ,vis
[maxN
], ans
[maxN
];
void init()
{
memset(num
, 0, sizeof(num
));
memset(vis
, 0, sizeof(vis
));
memset(ans
, 0, sizeof(ans
));
}
int main()
{
int n
, k
;
while(~scanf("%d%d", &n
, &k
))
{
int cnt
= 0;
init();
for(int i
= 1; i
<= n
; i
++ )
{
int a
, b
; scanf("%d%d", &a
, &b
);
for(int j
= a
; j
<= b
; j
++ )
{
info
[cnt
++ ] = node
{j
, b
, b
- j
+ 1, i
};
num
[j
] ++;
}
}
sort(info
, info
+ cnt
);
int pos
= 0;
for(int i
= 0; i
< cnt
; i
++ )
{
if(vis
[info
[i
].id
])
continue;
if(num
[info
[i
].l
] > k
)
{
for(int j
= info
[i
].l
; j
<= info
[i
].r
; j
++ )
num
[j
] -- ;
vis
[info
[i
].id
] = 1;
ans
[pos
++ ] = info
[i
].id
;
}
}
sort(ans
, ans
+ pos
);
printf("%d\n", pos
);
for(int i
= 0; i
< pos
; i
++ )
printf("%d%c", ans
[i
], " \n"[i
== pos
- 1]);
}
return 0;
}
D2. Too Many Segments (hard version)
思路
记录下输入的最左和最右的端点,跑for( i = L, i <= R )循环,以 i 为右端点,将左端点在 i 之前的线段都 insert,然后我们从这些线段里剔除右端点最靠右的几个,使得该点的出现频率 == k.【这里用到了贪心的思想,越往右,覆盖的点越多】在剔除线段之前,我们需要将右端点小于 i 的线段踢出去,因为前边的已经满足出现频率在 k 之内了【维护整数点的频率】用到了树状数组的区间更新,单点查询。【差分思想】
差分_树状数组
D[maxN]: D[ i ]表示 A[ i ] - A[ i - 1 ]求A[ i ] = D[ i ] + D[ i - 1 ] + D[ i - 2 ] + … + D[ 1 ]
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <list>
#include <map>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (- x)
using namespace std
;
typedef long long ll
;
typedef unsigned long long ull
;
const int maxN
= 2e5 + 5;
int n
, k
;
struct node
{
int l
, r
, id
;
node(int a
= 0, int b
= 0, int c
= 0) : l(a
), r(b
), id(c
) {}
friend bool operator < (node n1
, node n2
) { return n1
.r
> n2
.r
; }
}info
[maxN
];
bool cmp(node n1
, node n2
) { return n1
.l
< n2
.l
; }
int L
, R
;
int D
[maxN
];
void add(int x
, int val
)
{
while(x
<= R
)
{
D
[x
] += val
;
x
+= lowbit(x
);
}
}
int getsum(int x
)
{
int ans
= 0;
while(x
> 0)
{
ans
+= D
[x
];
x
-= lowbit(x
);
}
return ans
;
}
int main()
{
scanf("%d%d", &n
, &k
);
L
= INF
, R
= 0;
for(int i
= 1; i
<= n
; i
++ )
{
scanf("%d%d", &info
[i
].l
, &info
[i
].r
);
info
[i
].id
= i
;
L
= min(L
, info
[i
].l
);
R
= max(R
, info
[i
].r
);
}
for(int i
= 1; i
<= n
; i
++ )
{
add(info
[i
].l
, 1);
add(info
[i
].r
+ 1, -1);
}
sort(info
+ 1, info
+ n
+ 1, cmp
);
multiset
<node
>st
;
set
<int>ans
;
int pos
= 1;
for(int i
= L
; i
<= R
; i
++ )
{
if(getsum(i
) <= k
)
continue;
while(info
[pos
].l
<= i
&& pos
<= n
)
{
st
.insert(info
[pos
]);
pos
++;
}
while(!st
.empty() && (*st
.rbegin()).r
< i
)
st
.erase(*st
.rbegin());
while(st
.size() > k
)
{
node tmp
= *st
.begin();
ans
.insert(tmp
.id
);
st
.erase(st
.begin());
add(tmp
.l
, -1);
add(tmp
.r
+ 1, 1);
}
}
int cnt
= ans
.size();
printf("%d\n", cnt
);
while(!ans
.empty())
{
int tmp
= *ans
.begin();
printf("%d ", tmp
);
ans
.erase(tmp
);
}
printf("\n");
return 0;
}