CF1187D Subarray Sorting

题目

题目描述
You are given an array a_1, a_2, \dots, a_na
1

,a
2

,…,a
n

and an array b_1, b_2, \dots, b_nb
1

,b
2

,…,b
n

.

For one operation you can sort in non-decreasing order any subarray a[l \dots r]a[l…r] of the array aa .

For example, if a = [4, 2, 2, 1, 3, 1]a=[4,2,2,1,3,1] and you choose subbarray a[2 \dots 5]a[2…5] , then the array turns into [4, 1, 2, 2, 3, 1][4,1,2,2,3,1] .

You are asked to determine whether it is possible to obtain the array bb by applying this operation any number of times (possibly zero) to the array aa .

输入格式
The first line contains one integer tt ( 1 \le t \le 3 \cdot 10^51≤t≤3⋅10
5
) — the number of queries.

The first line of each query contains one integer nn ( 1 \le n \le 3 \cdot 10^51≤n≤3⋅10
5
).

The second line of each query contains nn integers a_1, a_2, \dots, a_na
1

,a
2

,…,a
n

( 1 \le a_i \le n1≤a
i

≤n ).

The third line of each query contains nn integers b_1, b_2, \dots, b_nb
1

,b
2

,…,b
n

( 1 \le b_i \le n1≤b
i

≤n ).

It is guaranteed that \sum n \le 3 \cdot 10^5∑n≤3⋅10
5
over all queries in a test.

输出格式
For each query print YES (in any letter case) if it is possible to obtain an array bb and NO (in any letter case) otherwise.

题意翻译
给定长度为 nn 的数组 aa 和 bb。你每次可以选择一段区间 [l,r][l,r],令 a_l\sim a_ra
l

∼a
r

的元素从小到大排序。你可以进行任意次操作。问能否使 aa 与 bb 完全相等(对应位置上的元素相等)。

输入输出样例
输入 #1复制
4
7
1 7 1 4 4 5 6
1 1 4 4 5 7 6
5
1 1 3 3 5
1 1 3 3 5
2
1 1
1 2
3
1 2 3
3 2 1
输出 #1复制
YES
YES
NO
NO
说明/提示
In first test case the can sort subarray a_1 \dots a_5a
1

…a
5

, then aa will turn into [1, 1, 4, 4, 7, 5, 6][1,1,4,4,7,5,6] , and then sort subarray a_5 \dots a_6a
5

…a
6

.

思路

一道不错的思维题。

我们从左往右考虑 b 的每一位,发现我们肯定要从 a 里找一个和这一位相同的拉过来。发现我们肯定是找还没有被用到的第一个。我们用队列维护一下每种数出现的位置即可。

考虑什么情况下可以被拉过来。发现当且仅当这个数前面所有没用过的数都比它大的时候它才能被拉过来。

我们再考虑怎么把它拉过来。可以像冒泡一样相邻两个进行一次操作,这样原来在它前面的所有数的顺序还是没有变的。感性理解一下,这样拉过来以后后面的怎么处理还是可以怎么处理,所以说如果这样不行那一定不行。

所以再看一下我们需要什么操作:

用队列维护每种数在 a 中出现的位置。
判断一个数前面所有没用过的数是否都比它大。
从“没用过的数”里删掉一个数。
对于删除操作,你写个平衡树当然也没问题。不过我们可以直接把这个数设成无穷大。这样我们需要的就是单点修改区间最值,直接上线段树就行。

代码

#include<cstdio>
#include<queue>
const int N=3e5+6;
int T,n,a[N],b[N],tot[N],pos[N];
std::queue<int>q[N];
int d[N<<2];
void build(int l,int r,int o){
	if(l==r)d[o]=a[l];else{
		const int mid=l+r>>1;
		build(l,mid,o<<1),build(mid+1,r,o<<1|1);
		d[o]=std::min(d[o<<1],d[o<<1|1]);
	}
}
int query(int l,int r,int o,const int&L,const int&R){
	if(L<=l&&r<=R)return d[o];
	const int mid=l+r>>1;
	if(L<=mid&&mid<R)return std::min(query(l,mid,o<<1,L,R),query(mid+1,r,o<<1|1,L,R));
	if(L<=mid)return query(l,mid,o<<1,L,R);return query(mid+1,r,o<<1|1,L,R);
}
void modify(int l,int r,int o,const int&pos){
	if(l==r)d[o]=9999999;else{
		const int mid=l+r>>1;
		if(pos<=mid)modify(l,mid,o<<1,pos);else modify(mid+1,r,o<<1|1,pos);
		d[o]=std::min(d[o<<1],d[o<<1|1]);
	}
}
int main(){
	for(scanf("%d",&T);T--;){
		scanf("%d",&n);
		for(int i=1;i<=n;++i)tot[i]=0;
		for(int i=1;i<=n;++i)scanf("%d",a+i),++tot[a[i]];
		for(int i=1;i<=n;++i)scanf("%d",b+i),--tot[b[i]];
		int ok=1;
		for(int i=1;i<=n&&ok;++i)if(tot[i]){
			puts("NO");ok=0;
		}
		if(!ok)continue;
		for(int i=1;i<=n;++i)
		q[a[i]].push(i);
		for(int i=1;i<=n;++i)pos[i]=q[b[i]].front(),q[b[i]].pop();
		build(1,n,1);
		for(int i=1;i<=n&&ok;++i){
			if(query(1,n,1,1,pos[i])!=b[i])ok=0;
			modify(1,n,1,pos[i]);
		}
		puts(ok?"YES":"NO");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值