P6283
USACO 2020 Open 银组 T3 The Moo Particle
题意
给定 \(n\) 个二维平面上的点,当一对点满足 \(x_i\leq x_j,y_i\leq y_j\) 时可以选择其中一个删掉。问最少可以留几个点。\(n\leq 10^5,-10^9\leq x,y\leq 10^9\)。
题解
注意到对所有能有关系的点对连边,最后答案就是连通块个数。因为连通块内部取一棵生成树,从叶子往根删就行,最后剩一个点。显然这样的复杂度是 \(O(n^2)\)。然后有更数学的做法。按 \((x,y)\) 双关键字排序,令 \(l_i=\min_{j=1}^i y_j,r_i=\max_{j=i}^n y_j\),当有 \(l_i>r_{i+1}\) 时就说明 \(i\) 之前的 \(y\) 最小值都大于 \(i\) 之后 \(y\) 最大值。这时因为 \(x\) 始终是单调的,就有 \(1\leq a\leq i,i+1\leq b\leq n\) 的所有 \(a,b\) 都满足 \(x_a\leq x_b,y_a>y_b\),这样 \(i\) 这个点肯定和前面的点不在同一连通块内。如此便可 \(O(n)\) 统计。最终复杂度为 \(O(n\log n)\),瓶颈在排序。aclink。
坑
- 注意值域范围,初始化 \(l,r\) 时要注意
inf的大小。
代码
#include<bits/stdc++.h>
#define i64 long long
#define L(a,b,c,d) for(int a=b;a<=c;a+=d)
#define R(a,b,c,d) for(int a=b;a>=c;a-=d)
using namespace std;
const int N=1e5+5;
void solve();
int n,l[N],r[N],ans;
pair<int,int> a[N];
signed main(){
int Test=1;
// scanf("%d",&Test);
while(Test--) solve();
return 0;
}
void solve(){
scanf("%d",&n);
L(i,1,n,1) scanf("%d%d",&a[i].first,&a[i].second);
sort(a+1,a+n+1);
l[0]=2e9;
L(i,1,n,1) l[i]=min(l[i-1],a[i].second);
r[n+1]=-2e9;
R(i,n,1,1) r[i]=max(r[i+1],a[i].second);
L(i,1,n-1,1){
if(l[i]>r[i+1]) ans++;
}
printf("%d\n",ans+1);
}
本文来自博客园,作者:jess1ca1o0g3,转载请注明原文链接:https://www.cnblogs.com/jess1ca1o0g3/p/19053030

浙公网安备 33010602011771号