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;
};
跑的飞快。