【区间交集的处理手法】P5464

P5464

推一推发现是一棵二叉树。

然后没啥用。

考虑处理区间的话,按端点排序会比较清晰地得出关系。按左端点排序。

\(f(l,r)\) 表示最右,次右端点分别为 \(R_r,R_l\) 地方案数。

对于区间 \(i\),显然要有 \(R_l\lt L_i\le R_r\),然后分类转移一下。\(\mathcal O(n^3)\)

cmd 题解里的一中高明枚举方法是,把第一维改成坐标而不是区间编号。

这样一遍加入 \(i\) 一边做前缀和,然后就可以完美地实现 \(\mathcal O(n^2)\) 地转移。比 BIT 暴力优化优雅很多。

#include <bits/stdc++.h>
#define pb emplace_back
#define fir first
#define sec second

using pii = std::pair<int, int>;

const int maxn = 2005;
const int mod = 1e9 + 7;

void add(int& x, int y) { if((x += y) >= mod) x -= mod; return ; }
void sub(int& x, int y) { if((x += y) >= mod) x -= mod; return ; }

int n, p, s[maxn << 1][maxn], ans;
pii a[maxn];

int main() {
	scanf("%d", &n);
	for(int i = 1;i <= n;++ i)
		scanf("%d %d", &a[i].fir, &a[i].sec);
	std::sort(a + 1, a + 1 + n);
	p = 1;
	for(int i = 1;i <= n;++ i) {
		while(p < a[i].fir) {
			for(int r = 1;r < i;++ r)
				add(s[p][r], s[p - 1][r]);
			++ p;
		}
		for(int r = 1;r < i;++ r)
			if(a[i].fir <= a[r].sec) {
				if(a[r].sec >= a[i].sec)
					add(s[a[i].sec][r], s[a[i].fir - 1][r]);
				else
					add(s[a[r].sec][i], s[a[i].fir - 1][r]);
			}
		++ s[0][i];
		for(int j = 1;j < p;++ j)
			add(s[j][i], s[j - 1][i]);
	}
	for(int i = p - 1;i <= 4000;++ i)
		for(int j = 1;j <= n;++ j)
			add(ans, s[i][j]);
	printf("%d\n", ans);
	return 0;
}
posted @ 2023-07-15 16:04  ImALAS  阅读(49)  评论(0)    收藏  举报