学长小清新题表之UOJ 180.实验室外的攻防战 线段树+三维偏序

学长小清新题表之UOJ 180.实验室外的攻防战

题目描述

时针指向午夜十二点,约定的日子——\(2\)\(28\)日终于到来了。随着一声枪响,伏特跳蚤国王率领着他的跳蚤大军们包围了 \(picks\) 博士所在的实验室。

当然,\(picks\) 博士不会坐以待毙,他早就率领着他的猴子们在实验室外修筑了许多的坚固防御工事。

经过跳蚤侦察兵的勘察,跳蚤国王发现 \(picks\) 博士的防御工事有着 \(n\)
处薄弱点,于是他把他的跳蚤大军分成了 \(n\) 支小队,并打算让它们分别进攻每一个薄弱点。但是因为战场混乱,这 \(n\) 支小队的位置被打乱了,重新整队之后,跳蚤国王发现第 \(i\)个位置的小队编号为 \(A_i\)(显然 \(A\)是一个排列)。

经过计算,跳蚤国王发现,让第 \(i\)个位置的小队编号为 \(Bi\) 时,他的军队可以发挥出最大的战斗力(保证 \(B\)也是一个排列)。

跳蚤国王可以发出指令来改变小队们的排列顺序,每一次,他都会报出一个整数 \(i(1≤i<n)\)。如果排在第 \(i\) 个位置的小队编号大于第 \(i+1\)

个位置的小队,那么这两支小队会交换顺序,否则这一个命令将会被忽略。

现在跳蚤国王希望他的军队能够发挥出最强大的战斗力,于是他想要知道是否存在一种指令序列,使得小队们可以按照排列 \(B\)的方式排列。

但是因为小队数目实在是太多,跳蚤国王一时间也没有看出答案。于是他派跳蚤绑架来了你——这附近最著名的民间科学家来帮他计算这个问题的答案。

输入格式

输入数据第一行包含一个正整数 \(n\)

接下来两行每行 \(n\)个正整数,分别描述排列 \(A\) 和排列 \(B\)
输出格式

对于每组数据,如果存在这样的指令序列,输出“YES”,否则输出“NO”(引号不输出,请注意大小写)。

样例一

input

3
2 3 1
2 1 3

output

YES

explanation

只要报出\(2\),也就是交换第\(2\)个位置和第\(3\)个位置的小队即可。

样例二

input

3
2 1 3
3 1 2

output

NO

explanation

注意只有相邻的满足前一个数大于后一个数的情况下才可以交换。

样例三

input

5
4 1 2 5 3
1 2 4 3 5

output

YES

explanation

步骤如下(每次交换的两个数加粗表示):

4 1 2 5 3

1 4 2 5 3

1 2 4 5 3

1 2 4 3 5

样例四

input

5
1 5 3 4 2
1 2 4 3 5

output

NO

样例五

input

8
8 2 7 4 5 3 6 1
2 8 5 7 4 3 6 1

output

NO

样例六

见样例数据下载。这组数据符合子任务 \(2\) 的限制与约定。

样例七

见样例数据下载。这组数据符合子任务 \(3\) 的限制与约定。

限制与约定

|子任务| 分值 |限制与约定|
|-|-|
|1 |24| \(n≤8\)|
|2| 32 |\(n≤1000\)|
|3 |44| \(n≤100000\)|

对于所有数据,\(1≤n≤100000\),保证输入的\(A\)\(B\)均为一个排列。

时间限制:\(1s\)

空间限制:\(256MB\)

分析

这一道题有点像

首先我们考虑什么样的情况是不存在的

很显然,在当前队列中,如果\(i\)\(j\)的左边,而在目标队列中\(i\)\(j\)的右边,并且\(i\)的值要小于\(j\)的值,那么就是不合法的

因为只有相邻的满足前一个数大于后一个数的情况下才可以交换

所以我们按照权值从小到大排好序,同时建立一个线段树,用在\(b\)序列中的位置当作下标,\(a\)序列中的位置当作权值

每次我们查询在\(b\)序列中下标大于当前值的元素在\(a\)序列中最小的下标,如果能查询到,就输出\(NO\)

否则在最后输出\(YES\)

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
inline int read(){
	register int x=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
struct asd{
	int val,wz;
}jl[maxn];
int a[maxn],b[maxn],rk[maxn],rkk[maxn];
bool cmp(asd aa,asd bb){
	return aa.val<bb.val;
}
struct trr{
	int l,r,val;
}tr[maxn];
void push_up(int da){
	tr[da].val=min(tr[da<<1].val,tr[da<<1|1].val);
}
void build(int da,int l,int r){
	tr[da].l=l,tr[da].r=r;
	if(l==r){
		tr[da].val=0x3f3f3f3f;
		return;
	}
	int mids=(l+r)>>1;
	build(da<<1,l,mids);
	build(da<<1|1,mids+1,r);
	push_up(da);
}
void xg(int da,int t,int w){
	if(tr[da].l==tr[da].r){
		tr[da].val=min(tr[da].val,w);
		return;
	}
	int mids=(tr[da].l+tr[da].r)>>1;
	if(t<=mids) xg(da<<1,t,w);
	else xg(da<<1|1,t,w);
	push_up(da);
}
int cx(int da,int l,int r){
	if(tr[da].l>=l && tr[da].r<=r){
		return tr[da].val;
	}
	int ans=0x3f3f3f3f,mids=(tr[da].l+tr[da].r)>>1;
	if(l<=mids) ans=min(ans,cx(da<<1,l,r));
	if(r>mids) ans=min(ans,cx(da<<1|1,l,r));
	return ans;
}
int main(){
	int n;
	n=read();
	build(1,1,n);
	for(register int i=1;i<=n;i++){
		a[i]=read();
		rkk[a[i]]=i;
	}
	for(register int i=1;i<=n;i++){
		b[i]=read();
		rk[b[i]]=i;
	}
	for(register int i=1;i<=n;i++){
		jl[i].val=a[i];
		jl[i].wz=rk[a[i]];
	}
	sort(jl+1,jl+1+n,cmp);
	for(register int i=1;i<=n;i++){
		int now=cx(1,jl[i].wz,n);
		if(now<rkk[jl[i].val]){
			printf("NO\n");
			return 0;
		}
		xg(1,jl[i].wz,rkk[jl[i].val]);
	}
	printf("YES\n");
	return 0;
}

posted @ 2020-08-15 15:29  liuchanglc  阅读(207)  评论(0编辑  收藏  举报