题目大意:有一个含有n个数的数组a和一个含有n个数的数组b,另有m个数,每次操作可以从m个数中取出一个数x,然后在a数组中选择一个连续的区间,使区间内的每一个数等于min(ai,x),问能否使所有a数组中的数都对应等于同位置上b数组的数
3<=n<=2e5;1<=ai<=1e9;1<=bi<=1e9;1<=m<=2e5;1<=xi<=1e9
思路:因为我们进行操作只能使ai变小,不能变大,所以我们选择的x作用的区间应该尽可能大同时其中不能有小于x的数,且如果整个数组中有bi>ai的情况,显然是没有合法解的。
所以我们在遍历b数组时,如果当前遍历的数比前边的数大,那么在这个数与另一个大于等于这个数之间的数都需要用x操作一次,所以我们对于这种需要对遍历到的数和上一个数之间作比较的问题可以用栈储存遍历b数组,然后用map统计每个数分别需要多少个x,因为数据范围太大所以不能用数组。
我们在输入b时,如果当前栈空,但如果当前遇到的数等于ai,那么这个数就不管,因为他不需要操作,如果小于ai,我们就把他放入栈中,在栈不空时,如果当前遇到的数小于栈顶数,也直接将这个数入栈。如果当前遇到的数大于栈顶元素,无论他是否等于ai,我们要用map统计栈内所有小于这个数的数量并弹出,然后如果这个数不等于ai,且栈空或者这个数不等于栈顶数就要将它入栈,因为如果这个数等于栈顶,这两个数中间都是小于它们的,可以用一个x即可,所有栈内不留相同元素,遍历结束后,我们再将栈内所有元素弹出并计数。
在输入x数组时,每输入一个数,就检查map中是否有对应数据,有就-1,-到0就删除这个元素,最后如果map为空则说明所有需要的x都能满足
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5;
int a[N];
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
stack<int>st;//储存b数组
map<int, int>ma;//记录每个数需要多少个x
bool flag = 1;//是否有bi>ai
for (int i = 1; i <= n; i++)
{
int x;
cin >> x;
if (x > a[i])
{
flag = 0;
}
if (!flag)//已经没有合法数据
continue;
if (st.empty() && x == a[i])//栈空且当前数=ai时不要将其入栈,其不需要x
continue;
if ((st.empty() || x < st.top()) && x != a[i])
{//当前数小于ai且栈空或当前数小于栈顶数就要将其入栈
st.push(x);
}
else if (x > st.top())
{//当前数大于栈顶,是区间右端点
while (!st.empty() && x > st.top())
{//当栈不空且当前数大于栈顶元素
int u = st.top();
ma[u]++;//记录需要的x数量
st.pop();//出栈
}
if ((st.empty() || x != st.top()) && x != a[i])
{//不能将两个相同的数入栈
st.push(x);
}
}
}
while (!st.empty())
{//统计栈内剩余数
int u = st.top();
ma[u]++;
st.pop();
}
int m;
cin >> m;
for (int i = 1; i <= m; i++)
{
int x;
cin >> x;
if (ma.find(x) != ma.end())
{//有数需要当前x
ma[x]--;//满足1个需求
if (ma[x] == 0)
{
ma.erase(x);//需求都被满足就删除这个元素
}
}
}
if (flag && ma.empty())
{//需求都被满足且没有bi>ai的情况
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
return 0;
}