2021 ICPC网络赛第一场**A Busiest Computing Nodes

2021 ICPC网络赛第一场A Busiest Computing Nodes

题意:

​ 有 k 个点( j = 0 , 1... k), n 个任务( i = 0 , 1... n),每个任务有到达时间和持续时间,第 i个任务从 i % k 的点开始往后找有没有空闲的点,如果没有找到则任务作废,问 k个点谁接的任务最多

思路:线段树+二分+set

线段树维护 k个点结束的区间最小值,单点修改,区间查询

把本来要先查询区间(i%k,k-1)(0,i%k-1)转变为查询区间(i%k,i%k+k),一共放入2*k个点;

二分查找最小值
set维护 k个点结束的最小值,判断是否任务需要遗弃

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10,INF=0x3f3f3f3f;
int cnt[N];int k,m;
int tr[N<<3],a[N<<2];//a存储第i个项目结束时间
set<int>s;
unordered_map<int,int>mp;
void build(int root,int l,int r){
    if(l==r){
        tr[root]=INF;
        return;
    }
    int mid = l + r >> 1;
    build(root << 1,l,mid);
    build(root << 1 | 1,mid+1,r);
    tr[root]=min(tr[root << 1],tr[root << 1 | 1]);
}
void update(int root,int l,int r,int x,int y){
    if(l>x||r<x){
        return ;
    }
    if(l==r&&l==x){
        tr[root]=y;
        return;
    }
    int mid = l + r >> 1;
    update(root << 1,l,mid,x,y);
    update(root << 1 | 1,mid+1,r,x,y);
    tr[root]=min(tr[root << 1],tr[root << 1 | 1]);
}
int query(int root ,int l,int r,int x,int y){
    if(l>y||r<x){
        return INF;
    }
    if(l>=x&&r<=y){
        return tr[root];
    }
    int mid = l + r >> 1;
    int mi;
    mi=min(query(root << 1,l,mid,x,y),query(root << 1 | 1,mid+1,r,x,y));
    return mi;
}
int f(int l,int r,int x){
    while(l<r){
        int mid = l + r >> 1;
        if(query(1,1,2*k,l,mid)<x){
            r=mid;
        }
        else l=mid+1;
    }
    return l;
}
signed main(){
    ios::sync_with_stdio(false);
    cin>>k>>m;
    build(1,1,2*k);//建树从1开始 
    s.insert(0);
    mp[0]=k;
    for(int i=0;i<m;i++){
        int st,time;
        cin>>st>>time;
        if(*s.begin()>=st) continue;//如果最小结束时间大于等于st当前仍无就废弃 
        if(a[i%k]<st){//第i%k个及其刚好可以进行这个任务 
            mp[a[i%k]]--;//之前结束时间的点减去1 
            cnt[i%k]++;//第i%k个点任务数+1 
            if(mp[a[i%k]]==0){//之前结束时间的点数为0,就把之前结束时间在s中除掉 
                s.erase(a[i%k]);
            }
            a[i%k]=st+time-1;//要更新结束时间 
            mp[a[i%k]]++;//新的结束时间的点+1 
            if(mp[a[i%k]]==1) s.insert(a[i%k]);//现在时间的点数为1,把这个时间放入s 
            update(1,1,2*k,(i%k)+1,a[i%k]);//跟新(i%k+1); 
            update(1,1,2*k,(i%k)+1+k,a[i%k]);//更新(i%k+1+k) 
        }
        else{
            int idx;
            idx=f(i%k+1,i%k+k,st);//把本来要先查询区间(i%k,k-1)(0,i%k-1)转变为查询区间(i%k,i%k+k) 
            idx--;
            idx%=k;
            mp[a[idx]]--;
            cnt[idx]++;
            if(mp[a[idx]]==0){
                s.erase(a[idx]);
            }
            a[idx]=st+time-1;
            mp[a[idx]]++;
            if(mp[a[idx]]==1) s.insert(a[idx]);
            update(1,1,2*k,(idx%k)+1,a[idx]);
            update(1,1,2*k,(idx%k)+1+k,a[idx]);
        }

    }
    int mx=0;
    for(int i=0;i<k;i++){
        mx=max(mx,cnt[i]);
    }
    int cnttt=0;
    for(int i=0;i<k;i++){
        if(cnt[i]==mx){
            if(cnttt){
                cout<<" "<<i;
            }
            else cout<<i;
            cnttt++;
        }
    }
}
posted @ 2021-09-27 22:47  Curry_BP  阅读(146)  评论(0)    收藏  举报