第十二届蓝桥杯省赛第二场C++A/B组 AcWing 3492. 负载均衡树状数组/堆

Posted nefu_ljw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十二届蓝桥杯省赛第二场C++A/B组 AcWing 3492. 负载均衡树状数组/堆相关的知识,希望对你有一定的参考价值。

题目链接

3492. 负载均衡

思路一

我的思路是先按机器分类,然后对每个机器进行处理。

对于每个机器,有一个开始时间a和持续时间c,消耗算力d。可以维护一个时间区间,其权值为这段时间内所消耗的算力。

将m个查询转化为离线查询。如果这个机器能分配到资源,就进行区间修改,即对[a,a+c]区间的算力+d,具体可以用树状数组维护(差分,区间修改+单点查询)。

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int tr[N],v[N];
void update(int i,int k,int n)
{
    while(i<=n)
    {
        tr[i]+=k;
        i+=i&(-i);
    }
}
int query(int i)
{
    int s=0;
    while(i)
    {
        s+=tr[i];
        i-=i&(-i);
    }
    return s;
}
struct node
{
    int id; // 原来的询问序号
    int a; // 开始时间
    int c; // 耗时
    int d; // 算力消耗
};
vector<node>g[N];
int ans[N],ta[N];
int main()
{
    ios::sync_with_stdio(false);
    int n,m,a,b,c,d;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i];
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b>>c>>d;
        g[b].push_back({i,a,c,d}); // 按机器分类
    }
    for(int i=1;i<=n;i++)
    {
        if(g[i].size())
        {
            //memset(tr,0,sizeof(tr)); 会超时
            int sz=g[i].size();
            for(int j=0;j<sz+6;j++)
            {
                ta[j]=g[i][j].a;
                tr[j]=0; // for循环清空树状数组,用memset超时
            }
            for(int j=0;j<sz;j++)
            {
                node it=g[i][j];
                int id=it.id;
                a=it.a;c=it.c;d=it.d;
                int p=j+1; // 右移到1~g[i].size
                int rest=v[i]-query(p); // 还剩多少算力可用
                if(rest>=d)
                {
                    ans[id]=rest-d; // 记录答案
                    // 结束时间a+c
                    int k=lower_bound(ta+j,ta+sz,a+c)-ta; // <a+c的第一个位置(-1再+1)
                    update(p,d,sz+5);
                    update(k+1,-d,sz+5);
                }
                else ans[id]=-1; // 记录答案
            }
        }
    }
    for(int i=1;i<=m;i++)
        printf("%d\\n",ans[i]);
    return 0;
}

自己想的这个思路,想复杂了,勉强能莽过去(1112 ms)。

思路二

从题解区看到的普遍做法。

对于每个机器维护一个堆,含有两个权值{结束时刻,消耗算力}。可以在线维护每个机器的算力变化,首先把当前机器的堆中的结束时刻小于当前机器开始时刻的全部弹出,同时恢复这些算力。 此后,如果能分配资源就直接把当前机器结束时刻和消耗算力加到堆中,否则输出-1即可。

#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q[N];
// 存每个机器的{结束时刻,消耗算力},按从小到大排序
int v[N];
int main()
{
    ios::sync_with_stdio(false);
    int n,m,a,b,c,d;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>v[i];
    for(int i=1;i<=m;i++)
    {
        cin>>a>>b>>c>>d;
        while(!q[b].empty()&&q[b].top().first<a) // 把结束时刻小于a的所有任务弹出,恢复算力
        {
            v[b]+=q[b].top().second; // 恢复算力
            q[b].pop(); // 弹出
        }
        if(v[b]<d)printf("-1\\n");
        else
        {
            q[b].push({a+c-1,d}); // 分配资源,实际上是持续到a+c-1而不是a+c
            v[b]-=d;
            printf("%d\\n",v[b]);
        }
    }
    return 0;
}

以上是关于第十二届蓝桥杯省赛第二场C++A/B组 AcWing 3492. 负载均衡树状数组/堆的主要内容,如果未能解决你的问题,请参考以下文章

第十二届蓝桥杯省赛第二场C++B组真题 未完结

第十二届蓝桥杯省赛第二场C++B组真题

第十二届蓝桥杯省赛第二场 C/C++ B组 编程题与详解

第十二届蓝桥杯省赛第一场C++ A/B/C组 真题题解(详细讲解 + 代码分析)看这篇就够了~~~~

第十二届蓝桥杯大赛软件赛省赛第二场C++B组

2021.5.9 第十二届蓝桥杯大赛软件赛省赛第二场大学B组(个人题解)