洛谷 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;
}

浙公网安备 33010602011771号