题目链接http://codeforces.com/contest/1187/problem/D
题意:
给出两个数组a,b,对数组a选任意多个子串进行排序,问能否构造出数组b
题解:
对于b[i],在数组a[i]中找到最左边且值相等的位置p,把a[p]两两交换地调到i这个位置。这样的话需要满足条件a[i]~a[p]<=a[p]。
开一个队列,记录每个权值所在的位置。判断区间最小值,一个线段树就行了。每次把a[p]赋一个无穷大,代表删去。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=3e5+7;
int t,n;
queue<int>q[N];
int mi[N<<2];
int a[N],b[N];
void bd(int rt,int l,int r){
if(l==r){mi[rt]=a[l];return;}
int m=l+r>>1;
bd(rt<<1,l,m);
bd(rt<<1|1,m+1,r);
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
void upd(int rt,int l,int r,int x,int val){
if(l==r){mi[rt]=val;return;}
int m=l+r>>1;
if(x<=m) upd(rt<<1,l,m,x,val);
if(m<x) upd(rt<<1|1,m+1,r,x,val);
mi[rt]=min(mi[rt<<1],mi[rt<<1|1]);
}
int que(int rt,int l,int r,int L,int R){
if(L<=l&&r<=R) return mi[rt];
int m=l+r>>1;
int res=n+1;
if(L<=m) res=min(res,que(rt<<1,l,m,L,R));
if(m<R) res=min(res,que(rt<<1|1,m+1,r,L,R));
return res;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
while(!q[i].empty()) q[i].pop();
}
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
q[a[i]].push(i);
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
}
bd(1,1,n);
bool flag=true;
for(int i=1;i<=n;i++){
if(q[b[i]].empty()){
flag=false;break;
}
int p=q[b[i]].front();q[b[i]].pop();
if(que(1,1,n,1,p)<b[i]){
flag=false;break;
}
upd(1,1,n,p,n+1);
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}