題目: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;
};
跑的飛快。