传送门
题意
给定一个长度为\(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;
}