2589. 完成所有任务的最少时间(区间取点——贪心or线段树)

简介: 2589. 完成所有任务的最少时间(区间取点——贪心or线段树)

模板题目

  • www.acwing.com/problem/con…
  • 题意是给一些区间,问至少取多少个点,让所有区间里至少有一个点
  • 上面这个是区间选点的模板贪心
  • 按照右端点排序,可以发现相邻的区间只有三种情况
  1. L2≤L1≤R1≤R2L_2 \leq L_1 \leq R_1 \leq R_2L2L1R1R2
  2. L1≤L2≤R1≤R2L_1 \leq L_2 \leq R_1 \leq R_2L1L2R1R2
  3. L1≤R1≤L2≤R2L_1 \leq R_1 \leq L_2 \leq R_2L1R1L2R2
  • 所以得出结论,贪心的想,选点在每个区间最后面开始,能满足最优的情况

题目

思路1————贪心

  • 这个就是上面题目的升级版,区间选点不再是一个,而是每个区间需要至少选一定数量的点
  • 同理,我们只需要用一个run数组来记录那些时间是被使用过的,然后从后往前补上确实的运行时间即可

代码

cpp

复制代码

class Solution {
public:
    int findMinimumTime(vector<vector<int>>& tasks) {
        sort(tasks.begin(),tasks.end(),[&](vector<int> &a,vector<int> &b)
        {
            return a[1] < b[1];
        });
        int run[2023] = {0};
        int ans = 0;
        for(auto task:tasks)
        {
            int l = task[0],r = task[1],ti = task[2];
            int has_run = 0;
            for(int i = l;i <= r;i ++)
            {
                has_run += run[i];
            }
            if(has_run >= ti)continue;
            for(int i = r;i >= l;i --)if(ti > has_run)
            {
                if(!run[i])
                {
                    has_run ++;
                    run[i] = 1;
                    ans ++;
                }
            }
        }
        return ans;
    }
};

思路2————贪心+线段树

  • 贪心思路和上面一样
  • 只不过用上了线段树的区间修改
  • 优先修改右子树
  • 找到从未更新过的子线段,然后判断是否数量足够、是否已满、是否被用过,然后再更新答案
  • 带入的更新value可以用引用
  • 然后返回,判断value > 0

代码

scss

复制代码

class Solution {
typedef long long LL;
const static int N = 2100;
// int n, m;
// int w[N];
struct Node
{
    int l, r;
    LL sum, add;//现实点数,子树有的lazy
}tr[N * 4];
void pushup(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u)
{
    auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    if (root.add)
    {
        //传递懒标记,更新子树
        left.add = root.add, left.sum = (LL) (left.r - left.l + 1) * root.add;
        right.add = root.add, right.sum = (LL) (right.r - right.l + 1) * root.add;
        //删除父结点懒标记
        root.add = 0;
    }
}
void build(int u, int l, int r)
{
    if (l == r) tr[u] = {l, r, 0, 0};
    else
    {
        tr[u] = {l, r};
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}
void modify(int u, int l, int r, int &v)//修改的modify
{
    if(tr[u].sum == tr[u].r - tr[u].l + 1)return ;
    if (l <= tr[u].l && tr[u].r <= r && tr[u].sum == 0 && tr[u].r - tr[u].l + 1 <= v)
    {
        v -= tr[u].r - tr[u].l + 1;
        tr[u].sum = (tr[u].r - tr[u].l + 1);
        tr[u].add = 1;
    }
    else
    {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (r > mid && v > 0) modify(u << 1 | 1, l, r, v);
        if (l <= mid && v > 0) modify(u << 1, l, r, v);
        
        pushup(u);
    }
}
LL query(int u, int l, int r)
{
    if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL v = 0;
    if (l <= mid) v = query(u << 1, l, r);
    if (r > mid) v += query(u << 1 | 1, l, r);
    return v;
}
public:
    int findMinimumTime(vector<vector<int>>& tasks) {
        sort(tasks.begin(),tasks.end(),[&](vector<int> &a,vector<int> &b)
        {
            return a[1] < b[1];
        });
        build(1,1,tasks.back()[1]);
        for(auto task:tasks)
        {
            int l = task[0],r = task[1],ti = task[2];
            ti -= query(1,l,r);
            if(ti > 0)modify(1,l,r,ti);
            
        }
        return query(1,1,tasks.back()[1]);
    }
};

最后

  • 又学到了新的线段树



相关文章
|
7月前
|
算法 测试技术 C#
【二分查找】【区间合并】LeetCode2589:完成所有任务的最少时间
【二分查找】【区间合并】LeetCode2589:完成所有任务的最少时间
|
7月前
|
算法 测试技术 C#
【折半处理 二分查找】1755. 最接近目标值的子序列和
【折半处理 二分查找】1755. 最接近目标值的子序列和
【折半处理 二分查找】1755. 最接近目标值的子序列和
|
7月前
|
人工智能 BI
区间问题之区间覆盖(看一遍就会系列)
区间问题之区间覆盖(看一遍就会系列)
|
算法
贪心算法——区间选点
贪心算法——区间选点
113 0
|
人工智能 算法 BI
贪心算法——区间选点与最大不相交区间数
贪心算法——区间选点与最大不相交区间数
77 0
|
人工智能 测试技术
poj 3061 快慢指针寻找最短区间
翻译过来简而言之就是 第1行 输入测试的案例个数 第 i 行 输入N和S (N代表数组长度,S代表目标和) 寻找最短区间满足区间之和大于或者等于S 第 i+1行 输入数组元素
区间选点(贪心)
这个题,虽然没有写过,但是我盲猜这个题肯定很经典
111 0
|
人工智能 算法
最大子列和的四种算法及其时间复杂度分析
最大子列和的四种算法及其时间复杂度分析 暴力破解法O(n^3)、暴力破解法改进版O(n^2); 分而治之法O(nlogn)、在线处理算法O(n)。
5164 0
最大子列和的四种算法及其时间复杂度分析