CF526 F Pudding Monsters

题意

求连续段数。
n<=3e5

思路

  • 析合树板题(然而并不会)
  • 考虑分治求。
  • 讨论max与min在左右两边的四种情况就行了。
  • O ( n l o g n ) O(n log n) O(nlogn)
#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值