原题链接
参考链接
题意: 给定 n n n个区间,问你可以被你看到的区间个数,按照输入顺序安排区间的前后顺序(输入顺序越后越能被看到)。

题解: 线段树+技巧离散化。这应该是线段树点表区间后的特殊技巧。(刚开始读错题,实际上一个数代表一个长度为1的区间)。我们将给定的区间左右端点离散化后,用线段树暴力。

但是会发现可能某个区间并没有被其他区间完全覆盖但却显示为被覆盖。如区间 [ 1 , 10 ] [ 1 , 4 ] , [ 6 , 10 ] [1,10][1,4],[6,10] [1,10][1,4],[6,10],离散化后 [ 1 , 4 , 6 , 10 ] [1,4,6,10] [1,4,6,10]对应 [ 1 , 2 , 3 , 4 ] [1,2,3,4] [1,2,3,4]。那么对应的离散化被覆盖区间为 [ 1 , 4 ] , [ 1 , 2 ] , [ 3 , 4 ] [1,4],[1,2],[3,4] [1,4],[1,2],[3,4](注意这里 2 2 2 3 3 3对应的是一个长度为 1 1 1的区间,故按照离散化的结果来看这里 [ 1 , 4 ] [1,4] [1,4] [ 1 , 2 ] , [ 3 , 4 ] [1,2],[3,4] [1,2],[3,4]完全覆盖,但是实际却没有。),与实际情况不符,那么可以想到时边界出现了问题。

手模几个例子会发现当两个点实际距离大于1的时候,即两者之间至少有一个块没被两者覆盖,所以我们只需要在两点距离大于2时添加一个点做边界,然后将真实区间插入线段树后进行查询即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;

const int N = 1e5 + 10, M = N << 2;
typedef pair<int, int> PII;
bool vis[M]; PII q[N]; 
int p[M], T, g, tn, n;
int tr[M], ans;

int b_s(int l, int r, int x) {
	while(l < r) {
		int mid = l + r >> 1;
		if(p[mid] >= x) r = mid;
		else l = mid + 1;
	}
	return l;
}

void pushdown(int u) {
	if(tr[u] != -1){ 
		tr[u << 1] = tr[u << 1 | 1] = tr[u];
		tr[u] = -1;
	} 
}

void modify(int u, int ul, int ur, int x, int y, int v) {
	if(ul >= x && ur <= y) {
		tr[u] = v;
		return ;
	}
	
	pushdown(u);
	int mid = ul + ur >> 1;
	if(y <= mid) modify(u << 1, ul, mid, x, y, v);
	else if(x > mid) modify(u << 1 | 1, mid + 1, ur, x, y, v);
	else modify(u << 1, ul, mid, x, mid, v), modify(u << 1 | 1, mid + 1, ur, mid + 1, y, v); 
}

void query(int u, int l, int r) {
	if(tr[u] != -1) {
		if(!vis[tr[u]]) {
			ans++;
			vis[tr[u]] = true;
		}
		return ;
	}
	
	if(l == r) return ;
	int mid = l + r >> 1;
	query(u << 1, l, mid);
	query(u << 1 | 1, mid + 1, r);
}

int main()
{
	scanf("%d", &T);
	while(T--) {
		memset(tr, -1, sizeof tr);
		memset(vis, false, sizeof vis);
		
		
		scanf("%d", &n);
		g = 0; tn = n * 2;
		for(int i = 1; i <= n; i++) {
			int a, b;
			scanf("%d%d", &a, &b);
			q[i] = {a, b};
			p[++g] = a; p[++g] = b;
		}
		
		sort(p + 1, p + 1 + tn);
		g = 0;
		for(int i = 1; i <= tn; ) {
			p[++g] = p[i];
			int j = i + 1;
			while(p[i] == p[j]) j++;
			i = j;
		}
		
		int len = g;
		for(int i = 2; i <= len; i++) 
			if(p[i] - p[i - 1] > 1) p[++g] = p[i - 1] + 1;
		sort(p + 1, p + 1 + g);
		
		for(int i = 1; i <= n; i++) {
			int x = b_s(1, g, q[i].first);
			int y = b_s(1, g, q[i].second);
			modify(1, 1, g, x, y, i);
		}
		
		ans = 0;
		query(1, 1, g);
		
		printf("%d\n", ans);
	}
	
	return 0;
}