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

来源:互联网 发布:学java可以找什么工作 编辑:程序博客网 时间:2024/05/17 15:39
题目描述:
 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 41 5 2 9 1 3 4 2 1 72 43 87 101 9
Output
178223210
Input
7 65 7 7 4 6 6 21 22 32 61 74 73 5
Output
202259168
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