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


跑的飞快。

posted @ 2021-09-20 22:35  萧瑟秋风今又是又是今  阅读(552)  评论(0编辑  收藏  举报