AcWing 362. 区间
听书上说有贪心 + 数据结构的做法,研究了一下。
朴素贪心
考虑把所有线段按照右端点 \(b\) 从小到大排序,依次考虑每一条线段的要求:
- 如果已经满足要求则跳过
- 否则尽量选择靠后的数(因为之后的线段的右端点都在这条线段的右边,这样容错更高)
所以,我们可以建一个数组,\(d[i]\) 表示 \(i\) 数字是否选择(填\(1\)或\(0\)),扫一遍 \([l, r]\) 区间求和,然后从后往前贪心放数即可。
对于每条线段需要 \(O(r - l + 1)\)。所以最坏情况下 \(O(n ^ 2)\)。但是轻松 \(52ms\) 过了。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50005;
int n, d[N], c[N];
struct Seg{
int a, b, c;
bool operator < (const Seg &x) const {
return b < x.b;
}
}e[N];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].c);
sort(e + 1, e + 1 + n);
int ans = 0;
for (int i = 1; i <= n; i++) {
int l = e[i].a, r = e[i].b, cnt = e[i].c;
for (int j = l; j <= r; j++)
cnt -= d[j];
if(cnt > 0) {
for (int j = r; j >= l && cnt; j--)
if(!d[j]) cnt--, ans++, d[j] = 1;
}
}
printf("%d\n", ans);
return 0;
}
优化
考虑用数据结构优化。
发现我们需要三个操作:
- 询问 \([l, r]\) 区间的数字个数
- 将值为 \(x\) 的位置 \(+1\)
- 从后往前,找到比当前位置靠前的下一个 \(0\) 的位置。
前两个就是 “区间求和,单调修改”,典型的树状数组。$O(nlog_250000) $
第三种操作,可以用并查集优化。为什么可以确保时间复杂度呢?对于每一条线段,最多只有一次会枚举到 \(1\) (即开始的那一次),之后每次枚举都会枚举到 \(0\) 的位置,即\(d[i] = 0\),然后把它变成 \(1\),而以后就不会访问到了。而一共有 \(50000\) 个值,所以复杂度是 \(O(50000log_n)\)
\(33ms\)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50001;
int n, d[N], c[N], f[N];
struct Seg{
int a, b, c;
bool operator < (const Seg &x) const {
return b < x.b;
}
}e[N];
// 树状数组
int inline ask(int x) {
int res = 0;
for (; x; x -= x & -x) res += c[x];
return res;
}
void inline add(int x) {
for (; x < N; x += x & -x) c[x]++;
}
// 并茶集:find(x) 表示找到 <= x 中最大的一个是 0 的数
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
int main() {
scanf("%d", &n);
for (int i = 0; i < N; i++) f[i] = i;
for (int i = 1; i <= n; i++)
scanf("%d%d%d", &e[i].a, &e[i].b, &e[i].c);
sort(e + 1, e + 1 + n);
int ans = 0;
for (int i = 1; i <= n; i++) {
int l = e[i].a, r = e[i].b, cnt = e[i].c;
// 取 [l, r] 选了多少个数
cnt -= ask(r) - ask(l - 1);
if(cnt > 0) {
for (int j = r; j >= l && cnt; ) {
// d[j] == 1 的情况每条线段至多出现一次
if(!d[j]) {
cnt--, ans++, d[j] = 1;
// j 被标记成 1 了,要指向 find(j - 1)
f[j] = j - 1;
// 维护树状数组
add(j);
};
if(find(j) != j) j = f[j];
else j--;
}
}
}
printf("%d\n", ans);
return 0;
}
AcWing 362. 区间的更多相关文章
- AcWing 803. 区间合并
网址 https://www.acwing.com/solution/AcWing/content/1590/ 题目描述给定n个区间[l, r]. 合并所有有交集的区间. 输出合并完成后的区间个数. ...
- Acwing‘803. 区间合并
(https://www.acwing.com/problem/content/805/) 给定 nn 个区间 [li,ri][li,ri],要求合并所有有交集的区间. 注意如果在端点处相交,也算有交 ...
- AcWing 802. 区间和
(https://www.acwing.com/problem/content/804/) 假定有一个无限长的数轴,数轴上每个坐标上的数都是0. 现在,我们首先进行 n 次操作,每次操作将某一位置x上 ...
- AcWing 802. 区间和 离散化
https://www.acwing.com/problem/content/804/ #include <iostream> #include <vector> #inclu ...
- AcWing 246. 区间最大公约数
246. 区间最大公约数 思路: 首先根据更相减损术,我们得到一个结论: \(gcd(a_l, a_{l+1}, ...,a_r) = gcd(a_l, a_{l+1}-a_l, a_{l+2}-a_ ...
- AcWing 906. 区间分组
//1.将所有区间按左端点从小到大排序 //2.从前往后处理每个区间,判断能否将其放到某个现有的组中 //判断某一组的最后一个区间的右端点是否小于该区间的左端点 //如果大于或等于,就开新组,如果小于 ...
- AcWing 907. 区间覆盖
//1.将所有区间按照左端点从小到大排序 //2.从前往后依次枚举每个区间 //首先选择能够覆盖左端点的区间当中右端点最靠右的端点 //在所有能覆盖start的区间当中,选择右端点最大的区间 //选完 ...
- AcWing 905. 区间选点
//1.将每个区间按右端点从小到大排序 //2.从前往后依次枚举每个区间,如果当前区间中已经包含点,就直接跳过,否则,选择当前区间的右端点 //选右端点的话,可以尽可能的包含在多个区间里 #inclu ...
- AcWing 803. 区间合并
#include <iostream> #include <vector> #include <algorithm> using namespace std; ty ...
随机推荐
- 《GNU_makefile》——第八章 内嵌函数
函数可以带参数,函数的展开方式和变量展开一样,函数的返回结果替换调用函数的文本. 1.函数的调用 $(FUNCTION ARGUMENTS) 或者: ${FUNCTION ARGUMENTS} FUN ...
- JAVA 去除字符串前后的指定字符
为了显示效果更好,我们可以将多余的字符去掉,代码如下: /** *去掉字符串前后的指定字符 */ public static String trimBothChars(String str, Stri ...
- 通过tuned-adm调整服务器的各种参数
前言 centos7 服务器上面支持通过tuned进行统一的系统参数调整,以前我们可能会通过修改内核配置文件修改内核参数,通过echo去调整磁盘预读,等等很多调整会分散在各处 而系统实际上是可以通过一 ...
- HotSpot源码分析之类模型
HotSpot采用了OOP-Klass模型描述Java的类和对象.Klass模型采用Klass类及相关子类的对象来描述具体的Java类.一般HotSpot JVM 在加载Java的Class 文件时, ...
- 03、MyBatis 映射文件
1.XML映射器 2.select Select元素来定义查询操作 Id:唯一标识符 - 用来引用这条语句,需要和接口的方法名一致 parameterType:参数类型 - 可以不传,MyBatis会 ...
- 01、Spring环境搭建
环境:SpringSource-Tool-3.9.9.Eclipse4.10.0 首先,我们需要解决的是Spring包的问题,我看了百度.CSDN很多都是直接一上来随便丢个包就可以安装了,搞得我弄了一 ...
- python-基础入门-1
Python的打印为 print,等价于c语言的printf 1 print "hello again" 就能打印出hello again,简简单单,就这么一句. 我用的vsc ...
- Elements-of-Python01_Input/Output
(内容包括输入input,输出print,注释comment,预测类型转换eval,命名与赋值Name & Bestow) 输入Input 和 输出Print Python中利用input() ...
- 你也想当流量UP主?那就点开看看吧!
2009年6月份,哔哩哔哩(B站)在一众期待中诞生,它汇聚了天南海北当时小众的二次元同好,它也存在诸多不足,大家亲切地叫它"小破站". 而如今,它成长为一棵枝繁叶茂的参天大树,成为 ...
- Word 2013中如何直接调用MathType
相信有很多用户已经发现在使用Word 2013编辑文档时MathType无法直接调用,但是点击文档中的公式时能够跳出MathType公式编辑窗口,那么这是怎么回事呢?其实,这一问题也不是没有办法解决的 ...