洛谷 AT_abc309_f [ABC309F] Box in Box 题解

题目链接

虽然是三维偏序,但是只需要求存在性,所以并不需要 cdq。

首先,题目说了可以变换三个数的位置,那么直接从小到大排这三个数是最优的。接下来考虑如何维护这三维。

对于 \(h\),可以直接从小到大排序。

对于 \(w\),可以使用树状数组来确定。

对于 \(d\),由于已经维护好了前两个数,那么只需要看前面那些满足前两个数都满足严格小于的箱子里面,最小的 \(d\) 是否小于当前的 \(d\) 就行了。刚好维护 \(w\) 时用到了树状数组,我们可以直接那树状数组维护前缀最小值。

有一个需要注意的点是,由于题目要求的是严格小于,所以遇到相同的 \(h\) 时不能直接更新树状数组,这样会导致后面 \(h\) 相同时多计算答案,应等到相同的 \(h\) 计算完再统一更新。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int N=2e5+100;
const ll INF=1e14;
int n,b[N],s[N],sk;
ll tr[N];
unordered_map<int,int> um;
struct node
{
	int h,w,d;
}a[N];
bool cmp(node a1,node a2)
{
	return a1.h<a2.h;
}
int lowbit(int x)
{
	return x&(-x);
}
void update(int p,ll x)
{
	for(int i=p;i<=n;i+=lowbit(i)) tr[i]=min(tr[i],x);
}
ll query(int p)
{
	ll mi=INF;
	for(int i=p;i;i-=lowbit(i)) mi=min(mi,tr[i]);
	return mi;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		tr[i]=INF;
		scanf("%d%d%d",&a[i].h,&a[i].w,&a[i].d);
		if(a[i].w<a[i].h) swap(a[i].w,a[i].h);
		if(a[i].d<a[i].h) swap(a[i].h,a[i].d);
		if(a[i].d<a[i].w) swap(a[i].d,a[i].w);
		b[i]=a[i].w;
	}
	sort(a+1,a+n+1,cmp);
	sort(b+1,b+n+1);
	for(int i=1;i<=n;i++) um[b[i]]=i+1;
	for(int i=1;i<=n;i++)
	{
		if(query(um[a[i].w]-1)<a[i].d) 
		{
			printf("Yes");
			return 0;
		}
		s[++sk]=i;
		if(i==n||a[i].h!=a[i+1].h)
		{
			while(sk) 
			{
				update(um[a[s[sk]].w],a[s[sk]].d);
				sk--;
			}
		}
	}
	printf("No");
	return 0;
}
posted @ 2025-06-14 14:30  MinimumSpanningTree  阅读(0)  评论(0)    收藏  举报