暑假热身C题

本文介绍了一道 CodeForces 竞赛题目的解题思路与实现方法,通过遍历目标数组并利用线段树和队列来判断源数组是否能通过子数组排序操作转换为目标数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://codeforces.com/problemset/problem/1187/D
You are given an array a1,a2,…,an and an array b1,b2,…,bn.

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

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

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

Input
The first line contains one integer t (1≤t≤3⋅105) — the number of queries.

The first line of each query contains one integer n (1≤n≤3⋅105).

The second line of each query contains n integers a1,a2,…,an (1≤ai≤n).

The third line of each query contains n integers b1,b2,…,bn (1≤bi≤n).

It is guaranteed that ∑n≤3⋅105 over all queries in a test.

Output
For each query print YES (in any letter case) if it is possible to obtain an array b and NO (in any letter case) otherwise.

Example
Input
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
Output
YES
YES
NO
NO
Note
In first test case the can sort subarray a1…a5, then a will turn into [1,1,4,4,7,5,6], and then sort subarray a5…a6.
给定两个数组a,b,可以对a数组任意子数组进行由小到大的排序,问能否变成b数组
遍历b数组,找到bi数字在a数组中的第一个位置loc,取a中1到loc最小值,最小值如果小于bi,则a无法变成b数组,然后将该位置数字变为INF
用队列储存位置,用线段树访问最小值,直接用a【N】储存会TLE,所以建树的时候顺便输入(谢谢队友提醒所以一发过了hhh)

#include<stdio.h>
#include<algorithm>
#include<queue>
#define N 300005
#define INF 0x3f3f3f3f
using namespace std;
int mi[N<<2],b[N],n,t;		
queue<int> q[N];
void build(int l,int r,int k)
{
	if(l==r)
	{
		scanf("%d",mi+k);
		q[mi[k]].push(l);
		return;
	}	
	else
	{
		int mid=(l+r)/2;
		build(l,mid,k<<1);
		build(mid+1,r,k<<1|1);
		mi[k]=min(mi[k<<1],mi[k<<1|1]);
	}
}
void oporate(int l,int r,int k,int loc)
{
	if(l==r)
	{
		mi[k]=INF;
		return;
	}
	
	int mid=(l+r)/2;
	if(loc<=mid)
	oporate(l,mid,k<<1,loc);
	else
	oporate(mid+1,r,k<<1|1,loc);
	mi[k]=min(mi[k<<1],mi[k<<1|1]);
}
int query(int l,int r,int k,int L,int R)
{
	if(l>=L&&R>=r)
	return mi[k];
	int mid=(l+r)/2;
	int te=INF;
	if(mid>=L)
	te=min(te,query(l,mid,k<<1,L,R));
	if(R>mid)
	te=min(te,query(mid+1,r,k<<1|1,L,R));
	return te;
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++) 
		{
			while(!q[i].empty()) 
			q[i].pop();
		}
        build(1,n,1);
		for(int i=1;i<=n;i++)
		scanf("%d",b+i);
		int flag=1;
		for(int i=1;i<=n;i++)
		{
			if(q[b[i]].empty())
			{
				flag=0;
				break;
			}
			int loc=q[b[i]].front();
			q[b[i]].pop();
			int temp=query(1,n,1,1,loc);
			if(temp<b[i])
			{
				flag=0;
				break;
			}
			oporate(1,n,1,loc);
		}
		if(flag)
		printf("YES\n");
		else
		printf("NO\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值