【lgj】【分治】【小清新】【单调性】

因为要求一段区间。所以对于一个点 uu,是否能被加入某段区间,设出边点集为 VuV_u,则只和 maxVu,minVumaxV_u,minV_u 有关。

这样用区间搞一遍是 O(n2)O(n^2)

对于某些区间计数问题,考虑分治。假设我们要求 [L,R][L,R] 区间的答案,分成 [L,mid],[mid+1,R][L,mid],[mid+1,R],求横跨两段的区间个数。

将两段分别探讨。

对于 [mid+1,R][mid+1,R] 区间中的 iimaxViRmaxV_i \leq R。这是可以扫一遍得到的,预处理出哪些 ii 是满足 [mid+1,i][mid+1,i]RR 的限制。

我们在左边也枚举 ii,观察 [i,mid][i,mid] 是否满足 LL 的限制。这时,我们考虑在左区间为 ii 的时候,右边的哪些数可以作为右端点。

他们要满足 [i,mid][i,mid] 区间在 RR 的限制,和 [mid+1,R][mid+1,R] 区间在 LL 的限制(称为第一,第二条限制)。他们都具有单调性。取 lmR,realRlmR,realR 分别表示 [lmR,R][lmR,R] 满足第一条限制,[mid+1,realR][mid+1,realR] 满足第二条限制。

这样我们就可以一次统计多个区间。复杂度 O(nlogn)O(n\log n)。主要是考虑了 min,maxmin,max 的单调性。

/*
	- 别摆了
	- By yfz
*/


#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10, mod = 1e9+7;
int n,m,Lv[N],Rv[N];

int sum[N];
int slove(int L,int R) {
	if(L == R) {
		if(Lv[L] == L && Rv[L] == L) return 1;
		return 0;
	}
	
	int mid = L + R >> 1;
	int tmp = (slove(L,mid) + slove(mid+1,R)) % mod;
	
	sum[mid] = 0;
	
	for(int i=mid+1,lmR = mid+1;i<=R;i++) {
		lmR = max(lmR, Rv[i]);
		sum[i] = sum[i-1];
		if(lmR == i) sum[i] ++;
	}
	
	for(int i=mid,lmR = mid+1,lmL = mid, realR = mid+1; i>=L ; i--) {
		lmL = min(lmL, Lv[i]); lmR = max(lmR, Rv[i]);
		while(realR <= R && Lv[realR] >= i) realR ++;
		realR --;
		if(lmL == i && realR >= lmR) {
			(tmp += sum[realR] - sum[lmR - 1]) %= mod;
		}
	}
	return tmp;
}
int main() {
//	freopen("graph3.in","r",stdin);
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++) Lv[i] = Rv[i] = i;
	for(int i=1,x,y;i<=m;i++) {
		cin>>x>>y;
		Lv[x] = min(Lv[x], y), Rv[x] = max(Rv[x], y);
	}
	
	cout << slove(1,n);
	return 0;
}
posted @ 2024-10-09 15:07  cjrqwq  阅读(8)  评论(0)    收藏  举报  来源