AcWing 362. Interval

He said that listening to books on covetousness + data structure of practice, study a little.

Plain greedy

Consider all line segments to the right end point \ (b \) from small to large, consider each line segment requirements:

  • If you already meet the requirements skip
  • Otherwise, try to choose the number of rearward (right end point because after all segments of the right of this segment, so higher fault tolerance)

Therefore, we can build an array, \ (D [I] \) represents \ (I \) whether a number is selected (fill \ (1 \) or \ (0 \) ), sweep over \ ([l, r] \ ) interval sum, then the number can be put forward from the greedy.

For each segment requires \ (O (R & lt -. 1 + L) \) . Therefore, in the worst case \ (O (^ n-2) \) . But easy \ (52ms \) before.

#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;
}

optimization

Consider a data structure optimization.

We need to find three things:

  • Inquiry \ ([l, r] \ ) digits interval
  • The value \ (X \) position \ (1 + \)
  • From back to front, front to find lower than the current position of a \ (0 \) position.
  1. The first two is "intervals are summed, monotonous Edit", typical of Fenwick tree. $ O (nlog_250000) $

  2. Third operation, may be disjoint-set optimization. Why can ensure that the time complexity of it? For each segment, at most only once to enumerate \ (1 \) (i.e., the start of that time), after each enumeration will enumerate \ (0 \) position, i.e., \ (d [i] = 0 \) , and then turn it into \ (1 \) , and then would not have access to the. And a total of \ (50,000 \) values, so complexity is \ (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;
}

Guess you like

Origin www.cnblogs.com/dmoransky/p/11923718.html