久违的eoj题解
思路来源
题面
单点时限: 3.0 sec
内存限制: 512 MB
章鱼王沿着国王大道巡视着他强大的王国,国王大道可以被看做一条直线,章鱼王的城堡的位置是 0 0 0。
章鱼王知道他的国家里有 n n n 个 WiFi 信号发射器,第 i i i 个发射器在 a i a_i ai 位置,代表章鱼王城堡向东 a i a_i ai 米(若 a i < 0 a_i<0 ai<0 则为向西),WiFi 的强度为 b i b_i bi,代表 a i a_i ai 处能接收到强度为 b i b_i bi 的信号,而与信号发射器距离每增加 1 1 1 米,信号强度就减少 1 1 1,直到信号为 0 0 0 就不再减少。
章鱼王有 q q q 个询问,他想知道在国王大道 c i c_i ci 位置处能接收到的最大信号强度。
输入格式
第一行为数据组数
T
(
T
≤
10
)
T(T\leq 10)
T(T≤10) 。
每组数据第一行为 n , q n,q n,q ,第二行为 n n n 个数字 a i a_i ai,第三行为 n n n 个数字 b i b_i bi,接下来一行 q q q 个询问 c i c_i ci。
保证
40
%
40\%
40% 的数据满足:
1
≤
n
,
q
≤
1000
1\leq n,q\leq 1000
1≤n,q≤1000。
保证
100
%
100\%
100% 的数据满足:
1
≤
n
,
q
≤
1
0
5
,
0
≤
∣
a
i
∣
≤
1
0
9
,
0
≤
b
i
≤
1
0
9
,
0
≤
∣
c
i
∣
≤
1
0
9
1\leq n,q\leq 10^5, 0\leq |a_i|\leq 10^9,0\leq b_i\leq 10^9,0\leq |c_i|\leq 10^9
1≤n,q≤105,0≤∣ai∣≤109,0≤bi≤109,0≤∣ci∣≤109。
所有数均为整数。
输出格式
对于每组数据中的每个询问,输出一行结果。
样例
input |
---|
1 2 3 0 6 3 6 0 -1 5 |
output |
3 2 5 |
思路分析
假设在位置
p
o
s
pos
pos 处的WiFi发射器的信号强度为
v
a
l
val
val,该WiFi发射器在点
x
x
x 处的信号强度为
p
p
p 。 则可得
p
=
v
a
l
−
∣
x
−
p
o
s
∣
=
{
v
a
l
+
p
o
s
−
x
(
x
左
边
)
v
a
l
−
p
o
s
+
x
(
x
右
边
)
p = val-|x-pos|=\left\{\begin{matrix}val+pos-x (x左边) \\ val-pos+x(x右边)\end{matrix}\right.
p=val−∣x−pos∣={val+pos−x(x左边)val−pos+x(x右边)
要求得
p
p
p 的最大值,即找到
x
x
x 左边
v
a
l
+
p
o
s
val+pos
val+pos 的最大值和
x
x
x 右边
v
a
l
−
p
o
s
val-pos
val−pos 的最大值。由于数据规模大,用顺序查找暴搜必然超时,所以采用二分查找。
对于
x
x
x左边的WiFi发射器,有
x
−
p
o
s
≥
0
x-pos \geq 0
x−pos≥0,
p
=
v
a
l
−
x
+
p
o
s
p = val - x + pos
p=val−x+pos ,那么我们只需二分查找找到
x
≥
p
o
s
x \geq pos
x≥pos的点在按
(
v
a
l
+
p
o
s
)
(val+pos)
(val+pos)键值排序的最后一个符合
x
≥
p
o
s
x \geq pos
x≥pos的Wifi发射器
同理,对于
x
x
x右边,
x
−
p
o
s
<
0
x-pos < 0
x−pos<0,
p
=
v
a
l
+
x
−
p
o
s
p = val + x - pos
p=val+x−pos,二分查找找到
x
<
p
o
s
x < pos
x<pos的点在按
(
v
a
l
−
p
o
s
)
(val-pos)
(val−pos)键值排序的最后一个符合
x
<
p
o
s
x < pos
x<pos 的Wifi发射器
但是当我们按照 v a l − p o s val-pos val−pos 或者 v a l + p o s val + pos val+pos 排序之后, p o s pos pos本身在数组中不一定是单调的。我们知道二分的前提是单调性。于是利用单调队列,在不影响原数组的顺序的情况下,处理出 p o s pos pos的单调性。
ac代码
#include<bits/stdc++.h>
using namespace std;
struct node
{
int pos,val;
};
bool cmp(node a,node b)
{
if(a.pos + a.val != b.pos + b.val)
return a.pos + a.val < b.pos + b.val;
return a.pos > b.pos;
}
bool cmp1(node a,node b)
{
if (a.val - a.pos != b.val - b.pos)
return a.val - a.pos < b.val - b.pos;
return a.pos < b.pos;
}
int n,q;
int main()
{
int T;
cin >> T;
while(T--)
{
cin >> n >> q;
node info[n], info1[n];
for(int i=0;i<n;i++)
{
cin >> info[i].pos;
info1[i].pos=info[i].pos;
}
for(int i=0;i<n;i++)
{
cin >> info[i].val;
info1[i].val=info[i].val;
}
//按照x左右不同键值排序
sort(info,info+n,cmp);
sort(info1,info1+n,cmp1);
//单调队列,left中的pos递增,right中pos递减。两个队列中键值都是递增
vector<node> left,right;
left.push_back(info[0]);
right.push_back(info1[0]);
for(int i=1;i<n;i++)
{
int rear=left.size()-1;
if(info[i].pos > left[rear].pos)
{
left.push_back(info[i]);
continue;
}
else if(info[i].pos < left[rear].pos)
{
//pos更小更易满足条件 x >= my[i].pos,且由于已经排序了p1会更大
while(left.size()&&info[i].pos<left[left.size()-1].pos)
left.pop_back();
left.push_back(info[i]);
}
}
for(int i=1;i<n;i++)
{
int rear=right.size()-1;
if(info1[i].pos < right[rear].pos)
{
right.push_back(info1[i]);
continue;
}
else if(info1[i].pos > right[rear].pos)
{
//pos更大更易满足条件 x < my[i].pos,且由于已经排序了p2会更大
while(right.size()&&info1[i].pos>right[right.size()-1].pos)
right.pop_back();
right.push_back(info1[i]);
}
}
int c;
while(q--)
{
cin >> c;
int p1=0,p2=0;
//二分查找
int l,r;
l=0,r=left.size()-1;
while(l < r)
{
int mid = (l+r+1)>>1;
if(left[mid].pos<=c)
l=mid;
else
r=mid-1;
}
if(left[l].pos<=c)
p1=max(0,left[l].pos+left[l].val-c);
l=0,r=right.size()-1;
while(l < r)
{
int mid = (l+r+1)>>1;
if(right[mid].pos>c)
l=mid;
else
r=mid-1;
}
if(right[l].pos>c)
p2=max(0,right[l].val-right[l].pos+c);
cout << max(p1,p2) << endl;
}
}
}