Loading

Minimal Segment Cover

前言

最近需要把效率提起来, 注意写题不能太水, 要多自己想

思路

转化题意
给定 \(n\) 个线段,每个线段形如 \([l,r]\)
\(m\) 次询问,每次询问给出 \(x, y\) , 求至少选多少个线段才能使这些线段的并能包含线段 \([x,y]\)

又是这一类线段题, 我们也是做过不少

不用想的太复杂, 我们先考虑一个贪心做法, 对于每一个点, 我们尽可能的往右边选择, 然后再跳到右边的位置之后继续贪心, 这样是 \(\mathcal{O} (nq)\)

考虑优化, 容易发现我们可以优化跳的次数, 类似于倍增

代码

#include <bits/stdc++.h>

const int MAXN = 5e5 + 10;
int n, q, f[MAXN][25], k;

int main()
{
    scanf("%d %d", &n, &q);
    for (int i = 1; i <= n; i++)
    {
        int l, r;
        scanf("%d %d", &l, &r);
        f[l][0] = std::max(f[l][0], r);
        k = max(k, r);
    }
    for (int i = 1; i <= k; i++)
        f[i][0] = std::max(f[i][0], f[i - 1][0]);
    for (int i = 1; i <= 20; i++)
        for (int j = 0; j <= k; j++)
            f[j][i] = f[f[j][i - 1]][i - 1];
    while (q--)
    {
        int l, r, ans = 0;
        scanf("%d %d", &l, &r);
        for (int i = 20; i >= 0; i--)
            if (f[l][i] < r)
            {
                ans += 1 << i;
                l = f[l][i];
            }
        printf("%d\n", f[l][0] >= r ? ans + 1 : -1);
    }
    return 0;
}

总结

倍增优化一类跳跃问题

posted @ 2024-12-16 08:29  Yorg  阅读(30)  评论(0)    收藏  举报