题目
思路
使用线段树单点修改,区间查询;
参考了这篇博客的思路;
但是不知道为什么我的代码跑的巨快,只用50+ms
思路就是拿一个vector数组来存结束的时间;
因为这个时间是比较大的,因此我们需要离散化处理一下;
遍历每一个事件的时候;
将时间 1 到 e v e n t [ i ] . a r r 1到event[i].arr 1到event[i].arr内的vector数组中的计算机释放出来;
查询的时候,先判断有无空闲节点;
如果没有直接抛弃;
否则
先查询 [ i d x , k ] [idx,k] [idx,k],如果查不到空闲的;再查询 [ 1 , i d x − 1 ] [1,idx-1] [1,idx−1];
将对应空闲电脑的下一次空闲时间丢入vector即可;
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
const int N = 1e5+10;
typedef long long ll;
struct Tree{
int l,r;
bool idle;
}tr[N<<2];
int k,n,bn,work[N],maxn,ansv[N],ansvn;
vector<ll> times;
vector<int> to_idle[N<<1];
ll b[N<<1],arr,pro;
struct Node{
ll arr,pro;
}event[N];
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
tr[p].idle = 1;
if(l == r){
return;
}
int mid = (l+r) >> 1;
build(lc,l,mid);
build(rc,mid+1,r);
}
void push_up(int p){
tr[p].idle = tr[lc].idle || tr[rc].idle;
}
void node_idle(int p,int x){
if(tr[p].l == tr[p].r){
tr[p].idle = 1;
return;
}
int mid = (tr[p].l + tr[p].r) >> 1;
if(x<=mid){
node_idle(lc,x);
}else{
node_idle(rc,x);
}
push_up(p);
}
//查询[l,r]中从左往右第一个空闲的点把它变的繁忙
int query_idle(int p,int l,int r){
if(tr[p].l == tr[p].r){
if(tr[p].idle){
tr[p].idle = 0;
return tr[p].l;
}else return -1;
}
int mid = (tr[p].l + tr[p].r) >> 1;
int ret = -1;
if(r<=mid){
if(tr[lc].idle) ret = query_idle(lc,l,r);
else ret = -1;
}else if(l>mid){
if(tr[rc].idle) ret = query_idle(rc,l,r);
else ret = -1;
}else{
if(tr[lc].idle){
ret = query_idle(lc,l,mid);
}
//之所以这里不能写else if(tr[rc].idle)
//因为比如一共5个数
//我们要找[3,5] 其中1有空,但是3没空,则[1,3]有空
//如果只找左边是找不到滴
if(ret == -1 && tr[rc].idle){
ret = query_idle(rc,mid+1,r);
}
}
push_up(p);
return ret;
}
void li_san_funct(){
//离散化
sort(times.begin(),times.end());
times.erase(unique(times.begin(),times.end()),times.end());
bn = times.size();
for(int i=1;i<=bn;++i){
b[i] = times[i-1];
}
}
int bfind(ll x){
int l = 1,r = bn,mid;
while(l<r){
mid = (l+r) >> 1;
if(b[mid]>=x){
r = mid;
}else l = mid+1;
}
return l;
}
int main()
{
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> k >> n;
for(int i=1;i<=n;++i){
cin >> arr >> pro;
event[i].arr = arr,event[i].pro = pro;
times.push_back(arr);
times.push_back(arr+pro);
}
li_san_funct();
build(1,1,k);
int init = 1;
for(int i=1,now;i<=n;++i){
now = bfind(event[i].arr);
while(init<=now){
//将休息的计算机标记
for(auto x : to_idle[init]){
node_idle(1,x);
}
++init;
}
if(tr[1].idle == 0){
//如果全员都在工作
continue;
}
//找到第一个不在工作的计算机
int L = (i-1)%k+1;
int ret = query_idle(1,L,k);
if(ret == -1){
ret = query_idle(1,1,L-1);
}
to_idle[bfind(event[i].arr+event[i].pro)].push_back(ret);
++work[ret];
}
for(int i=1;i<=k;++i){
maxn = max(maxn,work[i]);
}
for(int i=1;i<=k;++i){
if(work[i] == maxn){
ansv[++ansvn] = i-1;
}
}
for(int i=1;i<=ansvn-1;++i){
cout << ansv[i] << ' ';
}
cout << ansv[ansvn];
return 0;
}