题意:
给出两个长度为n的数组,可以把数组1中的一个区间内的数变为非降序(<=),询问数组1能否通过操作变成数组2
思路:
维护一下数组1的区间最小值并统计下每种数的下标(可以用队列之类),如果数组2中有一个数字x,如果x在数组1中的下标没有了,就说明两个数组的数字分布情况都不一样,肯定是不行了。有的话就取出最小的下标xpos,查询1-xpos区间的最小值,如果区间最小值要小于x,那么就不行了,因为这个比x小的数在数组2的位置是在x的后面,但是又比x要小,通过操作无法放到x的后面,显然就不满足条件了。如果区间最小值不小于x,那么更新xpos为极大值,区间更新,表示这个值已经被安排了。
参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
const int M=1e9+7;
int a[N],b[N];
int tree[N<<2];
queue<int>q[N];
#define lson rt<<1
#define rson rt<<1|1
void bulid(int rt,int l,int r){
if(l==r){
scanf("%d",&tree[rt]);
q[tree[rt]].push(l);
return;
}
int mid=(l+r)>>1;
bulid(lson,l,mid);
bulid(rson,mid+1,r);
tree[rt]=min(tree[lson],tree[rson]);
}
void update(int rt,int l,int r,int x,int k){
if(l==r&&l==x){
tree[rt]=k;
return;
}
int mid=(l+r)>>1;
if(x<=mid)update(lson,l,mid,x,k);
else update(rson,mid+1,r,x,k);
tree[rt]=min(tree[lson],tree[rson]);
}
int query(int rt,int l,int r,int x,int y){
if(l>=x&&r<=y){
return tree[rt];
}
int mid=(l+r)>>1;
if(y<=mid)return query(lson,l,mid,x,y);
else if(x>=mid+1) return query(rson,mid+1,r,x,y);
else return min(query(lson,l,mid,x,mid),query(rson,mid+1,r,mid+1,y));
}
int main(){
int t;
scanf("%d",&t);
for(int ca=1;ca<=t;ca++){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
while(!q[i].empty())q[i].pop();
}
bulid(1,1,n);
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
bool flag=true;
for(int i=1;i<=n;i++){
if(q[b[i]].empty()){
flag=false;
break;
}
int index=q[b[i]].front();
q[b[i]].pop();
int minn=query(1,1,n,1,index);
if(minn<b[i]){
flag=false;
break;
}
else{
update(1,1,n,index,M);
}
}
if(flag){
printf("YES\n");
}
else{
printf("NO\n");
}
}
return 0;
}