Loading

P6283

USACO 2020 Open 银组 T3 The Moo Particle

link

题意

给定 \(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);
}
posted @ 2025-08-22 16:19  jess1ca1o0g3  阅读(5)  评论(0)    收藏  举报