Lipshitz Sequence Codeforces Round #333 (Div. 1) B(单调栈)

题目描述:
 Lipshitz Sequence
time limit per test 1 second
memory limit per test 256 megabytes
input standard input
output standard output

A function is called Lipschitz continuous if there is a real constantK such that the inequality |f(x) - f(y)| ≤ K·|x - y| holds for all. We'll deal with a more... discrete version of this term.

For an array , we define it's Lipschitz constant as follows:

  • if n < 2,
  • if n ≥ 2, over all1 ≤ i < j ≤ n

In other words, is the smallest non-negative integer such that|h[i] - h[j]| ≤ L·|i - j| holds for all1 ≤ i, j ≤ n.

You are given an array of sizen andq queries of the form[l, r]. For each query, consider the subarray; determine the sum of Lipschitz constants ofall subarrays of.

Input

The first line of the input contains two space-separated integers n and q (2 ≤ n ≤ 100 000 and1 ≤ q ≤ 100) — the number of elements in array and the number of queries respectively.

The second line contains n space-separated integers ().

The following q lines describe queries. Thei-th of those lines contains two space-separated integersli andri (1 ≤ li < ri ≤ n).

Output

Print the answers to all queries in the order in which they are given in the input. For thei-th query, print one line containing a single integer — the sum of Lipschitz constants of all subarrays of.

Sample test(s)
Input
10 4
1 5 2 9 1 3 4 2 1 7
2 4
3 8
7 10
1 9
Output
17
82
23
210
Input
7 6
5 7 7 4 6 6 2
1 2
2 3
2 6
1 7
4 7
3 5
Output
2
0
22
59
16
8
Note

In the first query of the first sample, the Lipschitz constants of subarrays of with length at least2 are:

The answer to the query is their sum.

题目大意:

       规定了一个字符串的利普希茨常数L(h)为这个字符串数组中最大的(a[i]-a[j])/(i-j)的上取整的绝对值。之后给出最多100个询问,每次询问一个区间,问这个区间的每个子串的利普希茨常数之和是多少。

思路:

        观察利普西茨常数的表达式,发现(a[i]-a[j])/i-j 就是 f : i -> a[i] 这个离散函数的(i,a[i] ),( j,a[j]] )两点间连线的斜率,之后可以证明任意一个子串的两点间斜率的最大值,一定是由相邻的两个点产生的,因为如若不是这样,那么形成最大斜率的两点中间一定有其他的点,拿出这三个点来看,如果中间这个点在两点连线的下方,那么这个中间点和右边点的连线斜率会更大,矛盾,如果在上方,左边连线大,矛盾,如果在线上,那就一样大,也是可以由相邻两个点连线产生的。而且加了上取整这个结论一样是对的。

        有了这个简化,这个常数就是一个数组中相邻两点之差最大值了,先将所有相邻两点间之差存进数组,之后对这个正反两次单调栈处理出每个数右边的第一个比他大的数的下标还有左边的第一个比他大的数的下标,没有的就用INF代替,对于给定区间,那么所有的子区间的L( h ) 最大值之和就是计算的这些差值作为最大值的区间个数 * 这个差值再求和。

p.s.1.正反处理的时候为了不重复计数,一个是单调减的栈,一个是非严格单调增的栈

      2.数据规模大,要用longlong

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<stack>
#define INF 0x3f3f3f3f
#define MAX 1000005
#define ll long long
#define F(a) for(int i=2;i<=a;i++)
#define F_(a) for(int i=a;i>1;i--)
using namespace std;
stack<int>s;
ll a[MAX],r[MAX],l[MAX];//相邻数差值,右边第一个比他大的数的下标,左边第一个比他大的数的下标
int main()
{
	int n, q,s0,s1;
	scanf("%d%d%d", &n, &q, &s0);
	F(n)
	{
		scanf("%d", &s1);
		a[i] = abs(s1 - s0);
		s0 = s1;
	}
	F(n)
	{
		while (!s.empty() && a[s.top()] < a[i])
		{
			r[s.top()] = i;
			s.pop();
		}
		s.push(i);
	}
	while (!s.empty())
	{
		r[s.top()] = INF;
		s.pop();
	}
	F_(n)
	{
		while (!s.empty() && a[s.top()] <= a[i])
		{
			l[s.top()] = i;
			s.pop();
		}
		s.push(i);
	}
	while (!s.empty())
	{
		l[s.top()] = -INF;
		s.pop();
	}
	while (q--)
	{
		ll st, e,ans=0;
		scanf("%I64d%I64d", &st, &e);
		for (ll i = st + 1; i <= e; i++)
			ans += (min(e + 1, r[i]) - i)*(i - max(st, l[i]))*a[i];
		printf("%I64d\n", ans);
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值