Codeforces Round #731 (Div. 3) E题解

传送门

题意

给定一个长度为\(n\)的一维区间,区间里有\(k\)个空调,不存在重合的情况。每个空调能在其位置\(a\)上造成温度\(t\),每远离该位置\(1\)个单位距离,温度上升\(1\)。每个点的温度是所有的空调在这里造成的温度的最小值。

思路

易知往右边的位置,是左边的空调的最小值加上\(1\),右边的空调最小值减去\(1\),因此我们考虑:

  • \(a[j] < i\),此时往右移时,是所有\(a[j] < i\)的空调的最小值加上\(1\)
  • \(a[j] > i\),此时往右移时,是所有\(a[j] > i\)的空调的最小值加上\(1\)
  • \(a[j] = i\),此时往右移时,当前位置的空调本来在左边,但是变成了右边,所以右边的最小值需要取一个\(min\),右边同时要取移除这个空调之后的最小值

综上所述,我们可以使用单调队列维护所有空调的最小值,然后从左到右遍历每一个位置,遇到一个空调,就将其从队列中弹出,并维护左边的最小值,答案就是左边和右边的值的最小值。

代码

int n, k;
struct CON
{
    int a, t;
    bool operator < (const CON &x) {return a < x.a;}
}c[N];
PII b[N];
pair<bool, int> st[N];
int res[N];
int q[N];
 
int main()
{
    int T;
    cin >> T;
    while (T --  ) 
    {
        cin >> n >> k;
        for (int i = 1; i <= k; i ++ ) cin >> c[i].a;
        for (int i = 1; i <= k; i ++ ) cin >> c[i].t;
 
        sort(c + 1, c + 1 + k);
        for (int i = 1; i <= k; i ++ ) st[c[i].a] = {true, i};
 
        int l = 0x3f3f3f3f;
 
        int hh = 0, tt = -1;
        for (int i = 1; i <= k; i ++ ) 
        {
            while (hh <= tt && c[q[tt]].t + c[q[tt]].a - 1 > c[i].t + c[i].a - 1) tt -- ;
            q[++ tt] = i;
        }
 
        for (int i = 1; i <= n; i ++ )
        {
            if (st[i].x) 
            {
                int id = st[i].y;
                l = min(l, c[id].t + c[id].a - i);
                if (id >= q[hh]) hh ++ ;
                st[i].x = false;
            }
            if (hh <= tt) 
            {
                int id = q[hh];
                int r = c[id].t + c[id].a - i;
                res[i] = min(l, r);
            }
            else res[i] = l;
            l ++ ;
        }
 
        for (int i = 1; i <= n; i ++ ) cout << res[i] << ' ';
        cout << endl;
    }
    
    return 0;
}
上一篇:单调队列详解-小白入门数据结构必备


下一篇:认识python里的算术运算符