CF526 F Pudding Monsters

题意

求连续段数。
n<=3e5

思路

  • 析合树板题(然而并不会)
  • 考虑分治求。
  • 讨论max与min在左右两边的四种情况就行了。
  • O ( n l o g n ) O(n log n)
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10, Z = 3e5 * 2;
typedef long long ll;
int a[N], n;
int cnt[4 * N];
ll ans;
int b[N], no[N], len;

int smx[N], smi[N], pmx[N], pmi[N], omx[N], omi[N];

void divide(int L, int R) {
	if (L == R) ans++;
	if (L >= R) return;
	int mid = L + R >> 1;
	smx[mid + 1] = 0, smi[mid + 1] = n + 1;
	pmx[mid] = 0, pmi[mid] = n + 1;
	for(int i = mid + 1; i <= R; i++) {
		pmx[i] = max(pmx[i - 1], a[i]);
		pmi[i] = min(pmi[i - 1], a[i]);
	}

	for(int i = mid; i >= L; i--) {
		smx[i] = max(smx[i + 1], a[i]);
		smi[i] = min(smi[i + 1], a[i]);
	}

	int mi = mid, mx = mid;
	omx[mid] = omi[mid] = mid;
	for(int i = mid + 1; i <= R; i++) {
		while(mx >= L && smx[mx] <= pmx[i]) mx--;
		while(mi >= L && smi[mi] >= pmi[i]) mi--;
		omx[i] = mx, omi[i] = mi;
	}

	ll zs = 0;

	//part1
	for(int i = mid + 1; i <= R; i++) {
		int loc = i + pmi[i] - pmx[i];
		if (omi[i] < loc && omx[i] < loc && loc <= mid) zs++;
	}

	//part2
	for(int i = mid + 1; i <= R; i++) cnt[Z + i - pmx[i]] = 0;
	for(int i = mid + 1; i <= R; i++) {
		for(int j = omx[i - 1]; j > omx[i]; j--)
			cnt[Z + j - smi[j]] ++;
		for(int j = omi[i - 1]; j > omi[i]; j--)
			cnt[Z + j - smi[j]] --;
		if (omx[i] < omi[i]) zs += cnt[Z + i - pmx[i]];
	}

	//part3
	for(int i = mid + 1; i <= R; i++) cnt[Z + i + pmi[i]] = 0;
	for(int i = mid + 1; i <= R; i++) {
		for(int j = omx[i - 1]; j > omx[i]; j--)
			cnt[Z + j + smx[j]] --;
		for(int j = omi[i - 1]; j > omi[i]; j--)
			cnt[Z + j + smx[j]] ++;		
		if (omi[i] < omx[i]) zs += cnt[Z + i + pmi[i]];
	}

	//part4
	for(int i = mid + 1; i <= R; i++) cnt[Z + i] = 0;
	for(int i = L; i <= mid; i++) cnt[Z + smx[i] - smi[i] + i] ++;
	int zq = mid;
	for(int i = mid + 1; i <= R; i++) {
		while(zq > omx[i]){
			cnt[Z + smx[zq] - smi[zq] + zq] --;
			zq--;
		}
		while(zq > omi[i]) {
			cnt[Z + smx[zq] - smi[zq] + zq] --;
			zq--;
		}
		zs += cnt[Z + i];
	}
	ans += zs;
	divide(L, mid), divide(mid + 1, R);
}

int main() {
	freopen("f.in", "r", stdin);
	cin>>n; for(int i = 1; i <= n; i++) {
		int x,y;scanf("%d %d",&x,&y);
		a[x] = y;
	}
	divide(1, n);
	cout<<ans<<endl;
}

发布了266 篇原创文章 · 获赞 93 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/jokerwyt/article/details/102749949
今日推荐