Description
根据利普希茨条件定义一个长度为n的序列h的L(h)值:
n<2,L(h)=0;
n>=2,(1<=i< j<=n)
现给出一长度为n的序列a,给出q次查询,每次查询给出一个区间[l,r],求序列s={a[l],…,a[r]}的所有子序列L值之和
Input
第一行为两个整数n和q表示序列长度和查询次数,第二行n个整数ai表示这个序列,之后q行每行两个整数l和r表示查询区间(2<=n<=1e6,1<=q<=100,0<=ai<=1e8)
Output
对于每次查询,输出L(s)的值
Sample Input
10 4
1 5 2 9 1 3 4 2 1 7
2 4
3 8
7 10
1 9
Sample Output
17
82
23
210
Solution
设x1< x2< x3,y1< y2< y3,下面证明
不妨设,那么我们有
故
所以一个序列的L(h)=max( |h[i+1]-h[i]| )(1<=i< n),那么若求一个序列所有子序列L值之和,只需求出每个|h[i+1]-h[i]|的影响范围即可[l,r](即在这个区间内|h[i+1]-h[i]|最大),那么用单调栈即可解决这类问题
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 111111
typedef long long ll;
int n,q,a[maxn],b[maxn],s[maxn],top,L[maxn],R[maxn],l,r,len;
int main()
{
while(~scanf("%d%d",&n,&q))
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
while(q--)
{
scanf("%d%d",&l,&r);
len=r-l;
for(int i=l;i<r;i++)
b[i-l+1]=abs(a[i]-a[i+1]);
top=0;
for(int i=1;i<=len;i++)
{
while(top&&b[i]>=b[s[top]])top--;
L[i]=top==0?0:s[top];
s[++top]=i;
}
top=0;
for(int i=len;i>=1;i--)
{
while(top&&b[i]>b[s[top]])top--;
R[i]=top==0?len+1:s[top];
s[++top]=i;
}
ll ans=0;
for(int i=1;i<=len;i++)
ans+=1ll*(i-L[i])*(R[i]-i)*b[i];
printf("%I64d\n",ans);
}
}
return 0;
}