参考博客https://www.cnblogs.com/Dup4/p/11116198.html#d.-subarray-sorting
题意:
给两个数列a1,a2,……,an和b1,b2,……,bn。可以对a数列进行无限次区间排序,问是否能将a数列变成b数列。
思路:
记a数列中,a[i]前面比它大的元素的个数(类似于逆序数)为nx_a[i];b数列中,b[i]前面比它大的元素的个数为nx_b[i]。
要使a数列能够变成b数列,则对于任意i,nx_a[i] <= nx_b[i]。这两行瞎扯,与题解无关
可以用线段树来实现。
开一个nx数组,nx[t]记录在a排列中元素 t 的位置(是第几个)。如果有多个 t 则记录最前面那一个,并用 f 数组记下后一个的位置;如果a排列中没有元素t则nx[t] = INF,可以理解成把 t 放在了最后面。
而线段树则用来
- 记录(更新)每个元素在a排列中的位置。
- 查找区间内的元素在a排列中最靠前的位置。
最后,核心思路:
对于a[i]和a[j](a[i] > a[j]),如果nx[a[i]] < nx[a[j]],那么a[i]和a[j]一定无法交换位置。
所以,对于b[i],所有比b[i]小的元素(1 ~ b[i]-1)在a排列中的位置(即query())都应该在b[i]在a排列中的位置(即nx[b[i]])后面。
从第一个开始遍历b排列,先判断是否上一行成立。如果可,将b[i]元素在a排列中的最靠前位置(nx[b[i]]),更新到下一个b[i]的位置;否则return false。
#include<bits/stdc++.h>
#define MAXN 300010
using namespace std;
static const int INF = 1e9;
int n, a[MAXN], b[MAXN], cnt[MAXN], f[MAXN], nx[MAXN], node[MAXN << 2];
inline int lson(int node){
return node << 1;
}
inline int rson(int node){
return node << 1 | 1;
}
void build(int rt, int l, int r){
node[rt] = INF;
if(l == r) return;
int mid = (l + r) >> 1;
build(lson(rt), l, mid);
build(rson(rt), mid + 1, r);
}
void update(int rt, int l, int r, int pos, int x){
if(l == r){ node[rt] = x; return;}
int mid = (l + r) >> 1;
if(pos <= mid) update(lson(rt), l, mid, pos, x);
else update(rson(rt), mid + 1, r, pos, x);
node[rt] = min(node[lson(rt)], node[rson(rt)]);
}
int query(int rt, int l, int r, int L, int R){
if(L > R) return INF;
if(L <= l && r <= R) return node[rt];
int mid = (l + r) >> 1, Min = INF;
if(L <= mid) Min = min(Min, query(lson(rt), l, mid, L, R));
if(mid < R) Min = min(Min, query(rson(rt), mid + 1, r, L, R));
return Min;
}
bool check(){
//memset(cnt, 0, sizeof(cnt)); 这样写会超时woc
for(int i = 1; i <= n; i++) cnt[i] = 0;
for(int i = 1; i <= n; i++){ ++cnt[a[i]]; --cnt[b[i]];}
for(int i = 1; i <= n; i++) if(cnt[i]) return false;
return true;
}
void Init(){
for(int i = 1; i <= n; i++) nx[i] = INF;
for(int i = n; i >= 1; i--){ f[i] = nx[a[i]]; nx[a[i]] = i;}
}
bool solve(){
if(!check()) return false;
Init();
build(1, 1, n);
for(int i = 1; i <= n; i++) update(1, 1, n, i, nx[i]);
for(int i = 1; i <= n; i++){//核心思路
if(query(1, 1, n, 1, b[i] - 1) < nx[b[i]]) return false;
nx[b[i]] = f[nx[b[i]]];
update(1, 1, n, b[i], nx[b[i]]);
}
return true;
}
int main(){
int T;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
printf(solve() ? "YES\n" : "NO\n");
}
return 0;
}