Loading

Mayor's posters

Mayor's posters

线段树+离散化

将海报覆盖的区间在线段树中进行标记,最后统计存在于树中的海报类型

由于本题的数据范围比较大,需要对坐标进行离散化。之后再递归的遍历每一个节点,将存在的标记存放到set中,最终set中元素的数量就是海报的类型

注意

  1. 离散化后,区间之间的相对宽度会发生变化,比如[1, 10000]离散化后,变成[1,2],显然后者的覆盖范围要远小于前者。这点要注意,所以格外添加\(l+1\)\(r+1\)
  2. 除了建树的过程外,对于访问子节点的操作都需要下放懒标记,所以在修改和询问时要push_down
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>

using namespace std;

typedef pair<int, int> PII;
constexpr int N = 2e5 + 100;

struct Node {
  int l, r;
  int t;
} tr[N * 4];

int n, g[N], cnt;
vector<PII> v(N);
set<int> se;

inline int get(int x) {
  return lower_bound(g + 1, g + cnt + 1, x) - g;
}

void build(int u, int l, int r) {
  tr[u] = {l, r};
  if (l == r) return;
  int mid = l + r >> 1;
  build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

inline void push_down(int u) {
  int &t = tr[u].t;
  if (t) tr[u << 1].t = tr[u << 1 | 1].t = t;
  t = 0;
}

void modify(int u, int l, int r, int t) {
  if (tr[u].l >= l && tr[u].r <= r) tr[u].t = t;
  else {
    push_down(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid) modify(u << 1, l, r, t);
    if (r > mid) modify(u << 1 | 1, l, r, t);
  }
}

void count(int u, int l, int r) {
  // printf("%d %d %d %d\n", u, tr[u].t, l, r);
  if (tr[u].t) se.insert(tr[u].t);
  if (l == r) return;
  push_down(u);
  int mid = l + r >> 1;
  count(u << 1, l, mid), count(u << 1 | 1, mid + 1, r);
}

int main() {
  int _T;
  scanf("%d", &_T);
  while (_T --) {
    scanf("%d", &n);
    v.clear();
    se.clear();
    cnt = 0;

    for (int i = 0; i < n; i++) {
      int l, r; scanf("%d%d", &l, &r);
      v.push_back({l, r});
      g[++cnt] = l, g[++cnt] = r, g[++cnt] = r + 1, g[++cnt] = l + 1;
    }
    sort(g + 1, g + cnt + 1);
    cnt = unique(g + 1, g + cnt + 1) - g;
    build(1, 1, cnt);
    
    for (int i = 0; i < v.size(); i++) {
      auto [l, r] = v[i];
      l = get(l), r = get(r);
      modify(1, l, r, i + 1);
    }
    count(1, 1, cnt);
    
    printf("%zd\n", se.size());
  }
  
  return 0;
}

set非离散化

从后往前,将当前海报覆盖的范围的点全部删除,枚举的区间存在部分端点在set中,代表该海报没有被完全覆盖

注意:假如要删除的区间是最右边的,那么当区间内的元素会始终小于区间右边端点,此时while循环不会停止,所以要格外假如r+1这个点。

#include <iostream>
#include <algorithm>
#include <set>
#include <cstdio>
#include <utility>
using namespace std;
typedef pair<int, int> PII;

const int N = 1e5 + 1000;

set<int> se;
PII q[N];
int n;

int main() {
  int _T;
  scanf("%d", &_T);
  
  while (_T --) {
    int res = 0;
    se.clear();
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
      int & l = q[i].first, &r = q[i].second;
      scanf("%d%d", &l, &r);
      se.insert(l), se.insert(r), se.insert(r + 1);
    }
    
    for (int i = n; i; i--) {
      int l = q[i].first, r = q[i].second;
      auto t = se.lower_bound(l);
      if (*t <= r) res++;
      
      while (*t <= r) {
        se.erase(t);
        t = se.lower_bound(l);
      }
    }
    printf("%d\n", res);
  }
  return 0;
}
posted @ 2022-03-23 19:00  Frank_Ou  阅读(30)  评论(0编辑  收藏  举报