[单调栈]1156E Special Segments of Permutation

题意:给一个1-n的排列, 你需要求出有多少个区间满足a[l] + a[r] = max(a[l] - a[r]);

 解题思路

首先记录每个数字的下标

然后用单调栈维护以 a[i] 为最高点的区间

然后枚举 a[i] 区间内较短一侧的数

因为1 - n 排列数值唯一且已经记录了位置, 所以可以 O(1) 的求出 (a[i] - 小区间内数 )是否在右侧区间中, 统计得解


代码:

/*
    Zeolim - An AC a day keeps the bug away
*/

//pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <sstream>
#include <map>
#include <ctime>
#include <vector>
#include <fstream>
#include <list>
#include <iomanip>
#include <numeric>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace std;
//using namespace __gnu_pbds;
//typedef tree <long long, null_type, less <long long>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define mp(x, y) make_pair(x, y)
const ld PI = acos(-1.0);
const ld E = exp(1.0);
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6 + 10;
const ll MOD = 1e9 + 7;

int arr[MAXN] = {0};

struct node
{
	int l, r, loc;
}pos[MAXN];

int main()
{
    //ios::sync_with_stdio(false);
    //cin.tie(0);     cout.tie(0);
    //freopen("D://test.in", "r", stdin);
    //freopen("D://test.out", "w", stdout);
	
	int n;

	cin >> n;

	for(int i = 1; i <= n; ++i)
		cin >> arr[i], pos[i].l = i, pos[i].r = i, pos[arr[i]].loc = i;

	stack <int> ST;
	
	arr[0] = arr[n + 1] = INF;
	 
	ST.push(0);

	for(int i = 1; i <= n; ++i) //单调栈求区间
	{
		while(!ST.empty() && arr[i] > arr[ST.top()]) ST.pop();
		pos[i].l = ST.top() + 1;
		ST.push(i);
	}

	while(!ST.empty()) ST.pop();

	ST.push(n + 1);
	
	for(int i = n; i >= 1; --i)
	{
		while(!ST.empty() && arr[i] > arr[ST.top()]) ST.pop();
		pos[i].r = ST.top() - 1;
		ST.push(i);
	}

	int ans = 0;

	for(int i = 1; i <= n; ++i)
	{
		if(i - pos[i].l <= pos[i].r - i) 
		{
			for(int j = pos[i].l; j < i; ++j) //枚举合法
				if(pos[arr[i] - arr[j]].loc > i && pos[arr[i] - arr[j]].loc <= pos[i].r)
					++ans;
		}
		else
		{
			for(int j = i + 1; j <= pos[i].r; ++j)
				if(pos[arr[i] - arr[j]].loc < i && pos[arr[i] - arr[j]].loc >= pos[i].l)
					++ans;
		}
	}

	cout << ans << '
';

    return 0;
}
原文地址:https://www.cnblogs.com/zeolim/p/12270366.html