Hướng dẫn giải của Bedao Regular Contest 07 - DEADLINE


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.

Tác giả: bedao

Subtask 1-2:

Để qua ~40%~ test đầu các bạn có thể xét từng ~k~ rồi xử lí độc lập như sau:

Sắp xếp ~k~ công việc đầu theo ~d_i~. Gọi ~S~ là tập heap_max lưu trữ các công việc chưa được làm Xét từng thời điểm ~d~ theo thứ tự giảm dần, đến ~d~ của việc nào thì ném việc đó vào tập ~S~. Sau khi ném xong thì chọn việc sẽ làm tại thời điểm ~d~ là một việc nào đó trong tập ~S~ (hiển nhiên là việc có p lớn nhất).

Subtask 3:

Ta sẽ tìm cách xây dựng mối liên kết giữa công việc ~k~ vào bài toán ~(k-1)~ công việc đã xét ở trước. Vậy, công việc ~k~ có 2 trường hợp thay đổi kết quả bài toán là :

~1)~ Công việc ~k~ có thêm vào tập các công việc được làm

~2)~ Công việc ~k~ thay thế một việc trong tập các công việc được làm

Để kiểm tra ~1)~ ta có điều kiện cần và đủ là (số lượng công việc có deadline bé hơn hoặc bằng ~i~) ~\leq i~ ~\{\forall~ ~i \in [1, \inf)\}~. Ta có thể xây dựng cây Segment Tree Max (Lazy Segment Tree), quản lí thời điểm và đặt trước cho phần tử thứ ~i~ là ~-i~. Từ đó, công việc ~k~ có thể thêm vào nếu phần tử lớn nhất trên cây SegTree bé hơn ~0~.

Còn nếu không đặt được thêm công việc ~k~ thì nó sẽ cố thay thế ~1~ việc nào đó trong tập được làm. Cách xử lí là ta sẽ thêm công việc ~k~ vào, lúc này trên cây SegTree sẽ có một số vị trí bằng ~1~ thì ta sẽ phải bắt buộc bỏ đi ~1~ công việc có p nhỏ nhất trong đoạn từ ~1~ đến vị trí đầu tiên mà bằng ~1~.

Code mẫu

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define all(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define ls(x) (x*2)
#define rs(x) (x*2+1)
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int maxn = 100000;
const int maxh = 10;
const int oo = 4e18;
int n;
int d[maxn+1], p[maxn+1];

int maxi[maxn*maxh], vtmax[maxn*maxh], l[maxn*maxh], r[maxn*maxh];
bool lazy[maxn*maxh];
int lazyAdd[maxn*maxh];
multiset<pii> jobs[maxn*maxh];

pii better(pii x, pii y) {
    if (x.first >= y.first) return x;
    return y;
}

pii merger(int x,int y) {
    return better({maxi[x], vtmax[x]}, {maxi[y], vtmax[y]});
}

void initIT(int i,int x,int y) {
    l[i] = x, r[i] = y, lazy[i] = false, lazyAdd[i] = 0;
    jobs[i].clear();
    if (x==y) {
        maxi[i] = -x;
        vtmax[i] = x;
    } else {
        int m = (x+y)/2;
        initIT(ls(i),x,m);
        initIT(rs(i),m+1,y);
        pii tmp = merger(ls(i), rs(i));
        maxi[i] = tmp.first;
        vtmax[i] = tmp.second;
    }
}

void pushIT(int i) {
    if (lazy[i]) {
        lazy[i] = false;
        maxi[i] += lazyAdd[i];
        if (l[i]!=r[i]) {
            lazy[ls(i)] = true;
            lazy[rs(i)] = true;
            lazyAdd[ls(i)] += lazyAdd[i];
            lazyAdd[rs(i)] += lazyAdd[i];
        }
        lazyAdd[i] = 0;
    }
}


void addValueIT(int i,int x,int y,int v) {
    pushIT(i);
    if (y<l[i] || x>r[i]) return;
    if (x<=l[i] && r[i]<=y) {
        lazy[i] = true;
        lazyAdd[i]+=v;
        pushIT(i);
        return;
    }
    addValueIT(ls(i),x,y,v);
    addValueIT(rs(i),x,y,v);
    pii tmp = merger(ls(i),rs(i));
    maxi[i] = tmp.first;
    vtmax[i] = tmp.second;
}


pii getMaxIT(int i,int x,int y) {
    pushIT(i);
    if (y<l[i] || x>r[i]) return {-oo, -oo};
    if (x<=l[i] && r[i]<=y) return {maxi[i], vtmax[i]};
    pii left = getMaxIT(ls(i),x,y);
    pii right = getMaxIT(rs(i),x,y);
    return better(left, right);
}

void addJobs(int i,int d,int p) {
    if (d<l[i] || d>r[i]) return;
    jobs[i].insert({p,d});
    if (l[i]!=r[i]) {
        addJobs(ls(i),d,p);
        addJobs(rs(i),d,p);
    }
}

void removeJobs(int i,int d,int p) {
    if (d<l[i] || d>r[i]) return;
    jobs[i].erase(jobs[i].find({p,d}));
    if (l[i]!=r[i]) {
        removeJobs(ls(i),d,p);
        removeJobs(rs(i),d,p);
    }
}

pii findWorstJob(int i,int x,int y) {
    if (y<l[i] || x>r[i]) return {oo, oo};
    if (x<=l[i] && r[i]<=y) {
        if (sz(jobs[i])==0) return {oo, oo};
        return (*jobs[i].begin());
    }
    pii left = findWorstJob(ls(i),x,y);
    pii right = findWorstJob(rs(i),x,y);
    return min(left, right);
}



main() {
    cin.tie(0)->sync_with_stdio(0);
    cin.exceptions(cin.failbit);
    cin >> n;
    rep(i,1,n+1) cin >> d[i] >> p[i];
    initIT(1,1,maxn);

    int res = 0;
    rep(i,1,n+1) {
        addValueIT(1, d[i], maxn, 1);
        addJobs(1, d[i], p[i]);
        res += p[i];
        pii tmp = getMaxIT(1, 1, maxn);
        if (tmp.first > 0) {
            pii worstjob = findWorstJob(1, 1, tmp.second);
            removeJobs(1, worstjob.second, worstjob.first);
            addValueIT(1, worstjob.second, maxn, -1);
            res-=worstjob.first;
        }
        cout << res << '\n';
    }
}

Bình luận

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.