2021 ICPC 第一場網絡賽 A Busiest Computing NodesA Busiest Computing Nodes


題目:A Busiest Computing Nodes(The 2021 ICPC Asia Regionals Online Contest)

1.計算機的維護:

我們維護一個線段樹在計算機的狀態上,然后按照時間來改變計算機的狀態,初始所有值為0。

在一個固定的時間,當一個計算機被占用時,我們就將計算機的狀態置為1,即不可用狀態,並且線段樹每個結點維護當前結點的子樹中是否存在狀態為0的結點,就可以知道這個結點以下是否有可用結點。

2.請求的處理:

我們再維護一個 \(vector<int> time[]\) ;的序列,其中第 \(time[i]\) 表示在時刻 \(i\) 重新回歸可用狀態的計算機編號。當我們時間走到某一個 \(time[i]\) 時,遍歷 \(time[i]\)\(vector\) 序列,將所有在 \(time[i]\) 重新回歸可用狀態的計算機更新為0狀態,即可用狀態。

對於單個請求,設我們需要占用得計算機為 \(idx\) 那么我們就需要在 \([idx , k-1]\) 的區間內查詢最左側的狀態0的計算計編號,我們只需要按照先左子樹,再右子樹的順序查詢即可。如果左子樹存在狀態為 \(0\) 的結點,那么遞歸查詢左子樹,並返回結點的 \(idx\) ,否則遞歸查詢右子樹。

如果我們在 \([idx , k-1]\) 范圍查不到,那么我們就在 \([0 , k-1]\) 范圍內查詢最左狀態0的計算機編號。查詢方法同上。

如果還未查到,說明不存在可用狀態的計算機,直接繼續處理下一個查詢。

如果查到了,那么就在線段樹中將該計算機狀態置 \(1\) ,即不可用狀態,再在 \(time[當前request處理完成時間]\) 的vector中加入該計算機。

3.時間的處理:

時間節點只會出現 $arrive Time $和 \(arriveTime+processTime\) 之間的比較,沒有其他的加減乘除,故直接離散化即可。總共不同的時間最多為 \(2*n\) 種不同的時間, \(time[]\) 顯然開的下。

4.時間復雜度分析:

我們從線段樹中每次置 0 或 1 的復雜度為 \(log_{2}(k)\),置0的次數顯然小於n,每一次置1都是要先將該計算機置 0 ,所以置 1 的次數小於置 0 的次數。故總共在線段樹上操作次數不超過 2n 。所以最后下來復雜度大致是 \(2nlog_{2}(k)\)

5.空間復雜度分析:

線段樹4倍k,\(vector<int> time[]\) 在最多時,所有點加入其中,不超過k個,即使有空vector占用,但時間的總數量不超過2*n個。故不會超空間。

6.代碼:(自己按照需求手搓的魔改線段樹)

#include<iostream>
#include<map>
#include<unordered_map>
//#include<map>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;

typedef long long ll;
const int maxn = 1e5 + 50;

//super tree
struct node {
    int l, r;
    int sum;
    int lson, rson;
} tree[maxn * 4];
int tot = 1;
int rrr;
void build(int now, int l, int r, int len) {
    //cout << l << " " << r << endl;
    //cout << len << endl;
    tree[now].l = l;
    tree[now].r = r;
    tree[now].sum = 0;
    if (l == r) {
        tree[now].lson = tree[now].rson = -1;
        return;
    }
    tree[now].lson = tot++;
    tree[now].rson = tot++;
    build(tree[now].lson, l, l + len - 1, len / 2);
    build(tree[now].rson, r - len + 1, r, len / 2);
}
int getIdx(int idx, int now) {
    if (tree[now].l > rrr)return -1;
    if (tree[now].l == tree[now].r) {
        tree[now].sum = 1;
        return tree[now].l;
    }
    int ret = -1;
    int lson = tree[now].lson, rson = tree[now].rson;
    if (tree[lson].sum == 0 && tree[lson].r >= idx) {
        ret = getIdx(idx, tree[now].lson);
    }
    if (ret == -1 && tree[rson].sum == 0 && tree[rson].l <= rrr) {
        ret = getIdx(idx, tree[now].rson);
    }
    if (tree[lson].sum == 1 && tree[rson].sum == 1) {
        tree[now].sum = 1;
    }
    return ret;
}
void add(int idx, int now) {
    int lson = tree[now].lson, rson = tree[now].rson;
    if (lson == -1) {
        tree[now].sum = 0;
        return;
    }
    if (tree[lson].r < idx) {
        add(idx, rson);
    } else {
        add(idx, lson);
    }
    if (tree[lson].sum == 0 || tree[rson].sum == 0) {
        tree[now].sum = 0;
    }
}


map<ll, int> ck;
vector<int> timeadd[2 * maxn];
int num[2 * maxn], numtot, cktot;
struct proc {
    int atime, stime;
} info[maxn];
int cnt[maxn];
int ans[maxn], anstot;
int main() {
    ios::sync_with_stdio(false);
    int k, n;
    int a, b;
    //freopen("1.in", "r", stdin);
    scanf("%d%d", &k, &n);
    rrr = k;
    int len = 1;
    while (len < k)len *= 2;
    build(0, 0, len - 1, len / 2);

    for (int i = 0; i < n; i++) {
        scanf("%d%d", &a, &b);
        info[i].atime = a;
        info[i].stime = a + b;
        num[numtot++] = a;
        num[numtot++] = a + b;
    }

    sort(num, num + numtot);
    int pre = -1;
    for (int i = 0; i < numtot; i++) {
        if (num[i] != pre) {
            ck[num[i]] = cktot++;
        }
    }
    for (int i = 0; i < n; i++) {
        info[i].atime = ck[info[i].atime];
        info[i].stime = ck[info[i].stime];
        //cout << info[i].atime << " " << info[i].stime << endl;
    }
    int now = 0;
    for (int i = 0; i < n; i++) {
        while (now <= info[i].atime) {
            for (int j = 0; j < timeadd[now].size(); j++) {
                add(timeadd[now][j], 0);
            }
            now++;
        }
        timeadd[info[i].atime].clear();
        if (tree[0].sum == 1) {
            continue;
        }
        int idx = getIdx(i % k, 0);
        if (idx == -1) {
            idx = getIdx(0, 0);
        }
        timeadd[info[i].stime].push_back(idx);
        //cout << idx << endl;
        cnt[idx]++;

    }

    int maxx = 0;
    for (int i = 0; i < k; i++) {
        if (cnt[i] == maxx) {
            ans[anstot++] = i;
        } else if (cnt[i] > maxx) {
            anstot = 0;
            ans[anstot++] = i;
            maxx = cnt[i];
        }
    }
    //cout<<maxx<<" "<<anstot<<endl;
    // << "ans:" << endl;
    for (int i = 0; i < anstot; i++) {
        if (i)cout << " ";
        cout << ans[i];
    } cout << endl;
    return 0;
};


跑的飛快。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM