Leetcode1606 找到处理最多请求的服务器(线段树解法)

12 篇文章 0 订阅
6 篇文章 1 订阅

分析:

将编号为0,1,..k-1,的k个服务器开始空闲的时间记做time[t],0<=t<k,刚开始所有的time都为0

对于一个arrival[i],令x=i%k,我们想要知道以j= x,x+1,...,k-2,k-1,0,1,...,x-2,x-1顺序下的第一个j,使得time[j]<=arrival[i],可以发现[x,k-1]为一个连续的区间,[0,x-1]也是一个连续的区间。相当于在服务器中先查询[x,k-1]区间,如果找到直接返回;否则再查询[0,x-1]区间。这样就能够按照顺序查找到第一个空闲时间小于等于请求到达时间的空闲服务器,然后更新该服务器的空闲时间为arr[i]+load[i]

注意:

因为线段树query的顺序是先左子树再右子树的,这样就能保证在区间[l,r]中首先查询到最左边的有效值。

class Solution {
public:
    const static int N=1e5+5;
    struct TreeNode{
        int l,r,time;   //l左边界,r右边界,从time时刻起 服务器开始空闲
    }tr[4*N];
    int cnt[N];
    void pushup(int u){
        tr[u].time= min(tr[u<<1].time,tr[u<<1|1].time);
    }
    void build(int u,int l,int r){
        if(l==r){
            tr[u]={l,r,0};
            return;
        }
        tr[u].l=l,tr[u].r=r;
        int mid=(l+r)>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
    }
    int query(int u,int l,int r,int time){    //查询以u为根节点,区间为[l,r],小于等于time的最小下标
        if(l>r||tr[u].time>time) return -1;
        if(tr[u].l==tr[u].r) {
            if(tr[u].time<=time&&tr[u].l>=l&&tr[u].r<=r) return tr[u].l;
            return -1;
        }
        int mid=(tr[u].l+tr[u].r)>>1;
        if(r<=mid){
            if(tr[u<<1].time<=time) return query(u<<1,l,r,time);
            else return -1;
        }else if(l>mid){
            if(tr[u<<1|1].time<=time) return query(u<<1|1,l,r,time);
            else return -1;
        }else {
            int ql=-1,qr=-1;
            if(tr[u<<1].time<=time) ql= query(u<<1,l,r,time);
            if(ql!=-1) return ql;  //如果[tr[u].l,mid]中有符合条件的,那么它的下标一定比[mid+1,tr[u].r]的下标小,直接返回答案即可
            if(tr[u<<1|1].time<=time)  qr= query(u<<1|1,l,r,time);
            return qr;
        }
    }
    void update(int u,int i,int time){    //将下标为i的开始空闲的时间更新为time
        if(tr[u].l==i&&tr[u].r==i){
            tr[u].time=time;
            return;
        }
        int mid=(tr[u].l+tr[u].r)>>1;
        if(i<=mid) update(u<<1,i,time);
        else update(u<<1|1,i,time);
        pushup(u);
    }
    vector<int> busiestServers(int k, vector<int>& arrival, vector<int>& load) {
        int n=arrival.size(),maxx=0;
        build(1,0,k-1);
        int pos,t;
        for(int i=0;i<n;i++){
            pos=i%k;
            t=query(1,pos,k-1,arrival[i]);
            if(t==-1) t= query(1,0,pos-1,arrival[i]);
            if(t!=-1){
                update(1,t,arrival[i]+load[i]);
                ++cnt[t];
                maxx=max(maxx,cnt[t]);
            }
        }
        vector<int>ans;
        for(int i=0;i<k;++i){
            if(cnt[i]==maxx) ans.emplace_back(i);
        }
        return ans;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值