Codeforces E67 D. Subarray Sorting
题目:
给你两个数组a[], b[],对第一个数组你可以选择任意一个区间[l,r]进行从小到大排序。问能不能将a数组经过多次操作变成b数组。
题解:
首先,我们能发现一个数要向前移动,只能前面的数比它大时才可以向前移。所以要想把a变成b相当于用a中的数构造b,扫一遍b对每一位b[i],在a中
找到第一个和b[i]相同的数a[k],要想移到b[i]位置这个a[k]要是从i到j的最小值。
如何快速找到每个a[j]呢?我们可以开n个queue,每个队列保存a[]中数的位置。每次对b[i]取queue[b[i]]的队头,就是位置k,如果我们每次使用一个数后把它从a[]
中删除掉,那只用判断a[k]是1~k的最小值就说明可以用a[k]构造b[i],这个可以用线段树取维护。每次删除相当于在线段树中把这一位设为INF.
代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for(ll i = a; i <= n; ++ i)
#define per(i, a, n) for(ll i = n; i >= a; -- i)
typedef long long ll;
const int N = 3e5 + 105;
const int mod = 998244353;
const double Pi = acos(- 1.0);
const int INF = 0x3f3f3f3f;
const int G = 3, Gi = 332748118;
ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
//
int T, n;
int a[N], b[N];
queue<int>sol[N];
struct Tree{
int l, r;
int minval;
}tree[N * 4];
void Pushup(int index){
tree[index].minval = min(tree[index << 1].minval, tree[index << 1 | 1].minval);
}
void Build(int l, int r, int index){
tree[index].l = l;
tree[index].r = r;
tree[index].minval = INF;
if(l == r){
tree[index].minval = a[l];
return;
}
int mid = (l + r) >> 1;
Build(l, mid, index << 1);
Build(mid + 1, r, index << 1 | 1);
Pushup(index);
}
void Updata(int l,int r,int index,int val){
if(tree[index].l == tree[index].r){
tree[index].minval = val;
return;
}
int mid = tree[index].l + tree[index].r >> 1;
if(l <= mid) Updata(l, r, index << 1, val);
if(r > mid) Updata(l, r, index << 1 | 1, val);
Pushup(index);
}
int query(int l, int r, int index){
if(l <= tree[index].l && tree[index].r <= r){
return tree[index].minval;
}
int mid = (tree[index].l + tree[index].r) >> 1;
int res = INF;
if(l <= mid) res = min(res, query(l, r, index << 1));
if(r > mid) res = min(res, query(l, r, index << 1 | 1));
return res;
}
int main()
{
scanf("%d",&T);
while(T --){
scanf("%d",&n);
for(int i = 1; i <= n; ++ i){
while(sol[i].size()) sol[i].pop();
}
for(int i = 1; i <= n; ++ i){
scanf("%d",&a[i]);
sol[a[i]].push(i);
}
Build(1, n, 1);
int flag = 0, k;
for(int i = 1; i <= n; ++ i){
int x; scanf("%d",&x);
if(flag) continue;
if(sol[x].size()){
k = sol[x].front(); sol[x].pop();
int tt = query(1, k, 1);
if(tt == x) Updata(k, k, 1, INF);
else flag = 1;
}
else flag = 1;
}
if(flag) printf("NO\n");
else printf("YES\n");
}
return 0;
}