QOJ #16122. Sorted Pairs

题目链接

我们把第 \(i\) 行的左右两个数定义为 \(x _ i\)\(y _ i\),先把所有行按 \(x _ i\) 排序。

首先答案不差过 \(n + 1\),可以这样构造:若存在两行 \(x _ i < x _ j\)\(y _ i < y _ j\),则可以位移 \(x _ j\)\(y _ i\);否则说明此时剩下的 \(k\)\(y _ i\) 是降序的,可以这样构造:\((y _ k, x _ k, y _ {k - 1}, x _ {k - 2}, y _ {k - 3}, x _ {k - 4}, \ldots)\)

然后注意到答案 \(\ge n\)。答案 \(= n\) 时每一行都恰好选一个,并且 \(x _ i, y _ i\) 交替选,注意这要求位移环长为偶数,位移的环可以看作在 \((x _ i, y _ i)\) 二维平面向左走和向上走。

把原序列按前缀最大值位置断成若干段,若存在奇数长度的段则答案 \(= n + 1\),否则对于每一段,从最左边开始,依次跳上面的最右边和左边的最下面,直到跳到最右边。剩下的点相邻两两配对,从右往左扫每一对,先跳 \(y _ i\) 较小值,再跳 \(y _ i\) 较大值。

时间复杂度 \(\text O (n \log n)\),使用桶排可以做到 \(\text O (n)\)

#include<cstdio>
#include<algorithm>
#include<vector>
#define N 1000005
using namespace std;

int T,n;
vector<vector<int>> ans;
struct row {
	int x,y;
	bool operator<(row a) {return x<a.x;}
} a[N];
namespace sol1 {
	bool cut[N];
	bool check() {
		int cur=n+1;
		for(int i=1;i<=n;i++) {
			cur=min(cur,a[i].y),cut[i]=cur==n-i+1;
		}
		int las=0;
		for(int i=1;i<=n;i++) {
			if(cut[i]) {
				if((i-las)&1) return 0;
				las=i;
			}
		}
		return 1;
	}
	int rm[N],dm[N];
	bool vis[N];
	void work(int l,int r) {
		int L=n-r+1,R=n-l+1;
		for(int i=l;i<=r;i++) vis[i]=0;
		for(int i=l;i<=r;i++) {
			rm[a[i].y]=i,dm[a[i].x-n]=i;
		}
		for(int i=R-1;i>=L;i--) {
			if(a[rm[i+1]].x>a[rm[i]].x) rm[i]=rm[i+1];
		}
		for(int i=l+1;i<=r;i++) {
			if(a[dm[i-1]].y<a[dm[i]].y) dm[i]=dm[i-1];
		}
		int p=l,w=0; vector<int> res;
		while(p!=r) {
			vis[p]=1;
			if(w==0) res.push_back(a[p].y),p=rm[a[p].y];
			else res.push_back(a[p].x),p=dm[a[p].x-n];
			w^=1;
		}
		vis[p]=1;
		if(w==0) res.push_back(a[p].y);
		else res.push_back(a[p].x);
		vector<int> re;
		for(int i=l;i<=r;i++) {
			if(!vis[i]) re.push_back(i);
		}
		if(!re.empty()) {
			int s=re.size(); reverse(re.begin(),re.end());
			for(int i=0;i<s;i+=2) {
				row sm=a[re[i]],la=a[re[i+1]];
				if(sm.y>la.y) swap(sm,la);
				res.push_back(sm.y),res.push_back(la.x);
			}
		}
		ans.push_back(res);
	}
	void solve() {
		printf("%d\n",n);
		for(int l=1,r=0;l<=n;l=r+1) {
			do r++; while(r<=n&&!cut[r]);
			work(l,r);
		}
	}
}
namespace sol2 {
	int top,st[N];
	void solve() {
		top=0,printf("%d\n",n+1);
		for(int i=1;i<=n;i++) {
			if(top&&a[i].y>a[st[top]].y) {
				int j=st[top--];
				ans.push_back(vector<int>{a[i].x,a[j].y});
			} else {
				st[++top]=i;
			}
		}
		if(top>0) {
			int w=0; vector<int> now{a[st[top]].y,a[st[top]].x};
			for(int i=top-1;i;i--) {
				w^=1;
				if(w==0) now.push_back(a[st[i]].x);
				else now.push_back(a[st[i]].y);
			}
			ans.push_back(now);
		}
	}
}
int main() {
	scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
		sort(a+1,a+n+1);
		ans.clear();
		if(sol1::check())sol1::solve();
		else sol2::solve();
		printf("%d\n",ans.size());
		for(auto u:ans) {
			printf("%d ",u.size());
			for(auto v:u) printf("%d ",v);
			puts("");
		}
	}
	return 0;
}
posted @ 2026-01-23 08:27  yemuzhe  阅读(12)  评论(0)    收藏  举报