链接:https://vjudge.net/problem/POJ-2528#author=swust20141567
题意:
n(n<=10000) 个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000) 。求出最后还能看见多少张海报。
思路:
离散化加线段树。
离散化降低区间,并且因为区间重叠,每两个差距大于1的位置中间加一个前一个数+1的数,确保答案正确。
代码:
#include <iostream> #include <memory.h> #include <vector> #include <map> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 1e5 + 10; struct Line { int _l, _r; }line[MAXN]; int num[MAXN * 4]; int segment[MAXN * 4]; int vis[MAXN]; void Push_down(int root) { if (segment[root]) { segment[root << 1] = segment[root]; segment[root << 1 | 1] = segment[root]; segment[root] = 0; } } void Update_tree(int root, int l, int r, int ql, int qr, int c) { if (ql > r || qr < l) return ; if (ql <= l && r <= qr) { segment[root] = c; return ; } int mid = (l + r) / 2; Push_down(root); Update_tree(root << 1, l, mid, ql, qr, c); Update_tree(root << 1 | 1, mid + 1, r, ql, qr, c); } int Query(int root, int l, int r, int w) { if (l == r) return segment[root]; int mid = (l + r) / 2; Push_down(root); if (w <= mid) return Query(root << 1, l, mid, w); else return Query(root << 1 | 1,mid + 1, r, w); } int main() { int t; scanf("%d", &t); while (t--) { memset(vis, 0, sizeof(vis)); memset(num, 0, sizeof(num)); memset(segment, 0, sizeof(segment)); int n; scanf("%d", &n); int cnt = 0; for (int i = 1;i <= n;i++) { scanf("%d%d", &line[i]._l, &line[i]._r); num[++cnt] = line[i]._l; num[++cnt] = line[i]._r; } sort(num + 1, num + 1 + cnt); int size = unique(num + 1, num + 1 + cnt) - (num + 1);//可用数目 int sum = size; for (int i = 2;i <= size;i++) if (num[i] - num[i - 1] > 1) num[++sum] = num[i - 1] + 1; sort(num + 1, num + 1 + sum);//处理过后的数组 for (int i = 1;i <= n;i++) { int ll = lower_bound(num + 1, num + 1 + sum, line[i]._l) - num; int rr = lower_bound(num + 1, num + 1 + sum, line[i]._r) - num; Update_tree(1, 1, sum, ll, rr, i); } int res = 0; for (int i = 1;i <= sum;i++) vis[Query(1, 1, sum, i)] = 1; for (int i = 1;i <= sum;i++) res += vis[i]; printf("%d ", res); } return 0; }