久违的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的单调性。
#include
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;
}
}
}