E. Connected Components

题目描述🥰

题目思路😀

根据题目的描述的不等式,我们两个点 i 和 j 之间有边,必须同时满足条件:aiajijbibj ,对不等式进行经典变式,可以得到边的两个条件

  • ai - i <= aj - j
  • bi -i >= bj - j

而这个实际上我们可以把ai - i作为线段的左端点,bi - i作为线段的右端点。

对于每一个线段的左端点进行从小到大的排序(为了后面循环枚举首先就满足第一个条件)

  • 如果左端点相同,那么就按右端点从大到小进行排序。(因为需要保证连通块尽可能少,所以我们肯定要右端点大的放前面,好构成第二个条件)

接着就是循环遍历每一个线段,我们使用栈来记录每一个连通块里面的 bi - i

  • 如果当前线段的右端点已经比当前栈顶的连通块的 bi -i 都大的时候,那么就需要新开一个连通块,直接把这个线段的右端点push进去即可
  • 如果当前的线段的右端点已经可以满足和当前栈顶的连通块有边的条件了,那么我们可以用借此机会检测之前的连通块是否可以和当前的栈顶部的连通块进行合并

最后答案就是我们的栈的大小,栈的大小就是连通块的数量。

AC代码🧠

struct edge {
  int l;
  int r;
  bool operator<(const edge& b) const {
    if (l == b.l) return r > b.r;
    return l < b.l;
  }
};
void solve() {
  int n;
  cin >> n;
  vector<edge> res;
  for (int i = 1; i <= n; i++) {
    int ai, bi;
    cin >> ai >> bi;
    res.push_back({ai - i, bi - i});
  }
  sort(res.begin(), res.end());
  stack<int> s;
  for (int i = 0; i < n; i++) {
    if (s.size()) {
      if (res[i].r > s.top()) {
        s.push(res[i].r);
      } else {
        int t = s.top();
        while (s.size() && res[i].r <= s.top()) s.pop();
        s.push(t);
      }
    } else
      s.push(res[i].r);
  }
  cout << s.size() << endl;
}

 

 posted on 2025-05-13 17:19  熙玺  阅读(45)  评论(0)    收藏  举报

Shu-How Zの小窝

Loading...