题目链接:https://cn.vjudge.net/problem/POJ-2528
题意:依次给你n区间,按照先来后到的方式,当前区间回覆盖之前的区间,求表面能看到的区间种类有多少个
线段树区间更新,单点查询
更新完所有区间之后,n次单点查询,为了pushdown
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <set>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int T, n;
int R[maxn], L[maxn], b[maxn << 1];
struct Tree{
int l, r, lazy, sum;
}e[maxn << 2];
inline void build(int l, int r, int cur){
e[cur].l = l;
e[cur].r = r;
e[cur].lazy = 0;
if(l == r) {
return ;
}
int mid = l + r >> 1;
build(l, mid, cur << 1);
build(mid + 1, r ,cur << 1 | 1);
}
inline void pushdown(int cur){
if(e[cur].lazy) {
e[cur << 1].lazy = e[cur << 1 | 1].lazy = e[cur].lazy;
e[cur].lazy = 0;
}
}
inline void update(int l, int r, int cur, int cl, int cr, int val){
if(l <= cl && cr <= r) {
e[cur].lazy = val;
return ;
}
pushdown(cur);
int mid = cl + cr >> 1;
if(l <= mid) update(l, r, cur << 1, cl, mid ,val);
if(r > mid) update(l, r, cur << 1 | 1, mid + 1, cr, val);
}
inline int query(int pos, int l, int r,int cur){
if(l == r) {
return e[cur].lazy;
}
pushdown(cur);
int mid = l + r >> 1;
if(pos <= mid) return query(pos, l, mid, cur << 1);
else return query(pos, mid + 1, r, cur << 1 | 1);
}
set<int> s;
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
int cnt = 0;
for(int i = 1; i <= n; i++) {
scanf("%d%d", &L[i], &R[i]);
b[cnt++] = L[i];
b[cnt++] = R[i];
}
sort(b, b + cnt);
cnt = unique(b , b + cnt) - b;
build(1, cnt , 1);
for(int i = 1; i <= n; i++) {
int l = lower_bound(b , b + cnt, L[i]) - b + 1;
int r = lower_bound(b , b + cnt, R[i]) - b + 1;
update(l, r, 1, 1, cnt, i);
}
for(int i = 1; i <= cnt; i++) {
int x = query(i, 1, cnt, 1);
if(x) s.insert(x);
}
printf("%d\n", s.size());
s.clear();
}
return 0;
}