uoj180 【UR #12】实验室外的攻防战

题目

我们发现对于排列\(A\)中,一组\(i<j,a_i<a_j\),那么我们不可能通过交换把\(a_j\)换到\(a_i\)前面

但是一组\(i<j,a_i>a_j\),我们却可以通过交换使得\(a_j\)更靠前,也就是我们在\(A\)中的交换只能消除一些逆序对,而不能产生新的逆序对

于是我们想要得到排列\(B\),必须使得\(B\)中的任意一个逆序对在\(A\)中也是逆序的,否则就不可能通过交换使得\(A\)变成\(B\);即一旦\(B\)中一个逆序对在\(A\)中是顺序的,我们就输出\(NO\)

之后就开始智商下降了,强行莫队+值域分块

我们对于一个数\(i\),我们设其在\(A\)中的出现位置为\(posa_i\),在\(B\)中出现的位置为\(posb_i\),那么我们就把\((posa_i,posb_i)\)视为一个点对,将\(A\)序列中的\([1,posa_i]\)的数都加入值域块,点权为\(1\)\([1,posb_i]\)的数也都加入值域块,点权为\(-1\),如果这个时候有一个大于\(i\)的点点权为\(-1\),那么就说明这个点在\(B\)中和\(i\)形成了逆序对,但是在\(A\)中却没有。所有点的加入可以通过莫队保证复杂度。

复杂度是\(O(n\sqrt{n})\),成功位列uoj倒数第五

代码

#include<bits/stdc++.h>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
	char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=1e5+5;
struct Point{int x,y,rk;}p[maxn];
int a[maxn],b[maxn],id[maxn],B,n,cnt,L[500],R[500];
int tax[maxn],tag[500];
inline void add(int x,int v) {
	tax[x]+=v;
	if(v==1&&tax[x]==0) tag[id[x]]--;
	if(v==-1&&tax[x]==-1) tag[id[x]]++;
}
inline int find() {
	for(re int i=cnt;i;--i) {
		if(!tag[i]) continue;
		for(re int j=R[i];j>=L[i];--j) 
			if(tax[j]==-1) return j;
	} 
	return 0;
}
inline int cmp(Point A,Point B) {return id[A.x]==id[B.x]?A.y<B.y:A.x<B.x;}
int main() {
	n=read();B=std::sqrt(std::ceil(n));
	for(re int i=1;i<=n;i++) p[i].rk=i;
	for(re int i=1;i<=n;i++) a[i]=read(),p[a[i]].x=i;
	for(re int i=1;i<=n;i++) b[i]=read(),p[b[i]].y=i;
	for(re int l=1,r;l<=n;l=r+1) {
		r=min(n,l+B-1);++cnt;L[cnt]=l,R[cnt]=r;
		for(re int j=l;j<=r;++j) id[j]=cnt;
	}
	std::sort(p+1,p+n+1,cmp);
	int l=0,r=0;
	for(re int i=1;i<=n;i++) {
		while(l<p[i].x) add(a[++l],1);
		while(l>p[i].x) add(a[l--],-1);
		while(r<p[i].y) add(b[++r],-1);
		while(r>p[i].y) add(b[r--],1);
		if(find()>p[i].rk) return puts("NO"),0;
	}
	puts("YES");
	return 0;
}

正解其实非常简单,我们维护一个树状数组,按照\(i\)从小到大把\((posa_i,posb_i)\)插入树状数组;插入之前查一下之前插入的\(j\)中满足\(posa_j<posa_i\)\(posb_j\)的最大值,如果这个最大值大于\(posb_i\),那么就说明了\(A\)中的一个顺序对在\(B\)中变成了逆序对,直接输出\(NO\)即可。

posted @ 2019-09-23 14:26  asuldb  阅读(125)  评论(0编辑  收藏  举报