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,下面证明
不妨设 ,那么我们有
故
根据利普希茨条件定义一个长度为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]|最大),那么用单调栈即可解决这类问题
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
using namespace std;
long long a[100005];
long long l[100005];
long long r[100005];
long long d[100005];
struct node
{
long long w;
int id;
};
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0; i<n; i++)
{
scanf("%lld",&a[i]);
}
for(int i=1; i<n; i++)
{
d[i]=abs(a[i]-a[i-1]);
}
stack<node> s;
for(int i=1; i<n; i++)
{
while(!s.empty() && d[i]>=s.top().w)
{
s.pop();
}
if(s.empty())
{
l[i]=0;
}
else
{
l[i]=s.top().id;
}
node nex;
nex.id=i;
nex.w=d[i];
s.push(nex);
//cout<<i<<" "<<l[i]<<endl;
}
while(!s.empty())
s.pop();
for(int i=n-1;i>=1;i--)
{
while(!s.empty() && d[i]>s.top().w)
{
s.pop();
}
if(s.empty())
{
r[i]=n-1;
}
else
{
r[i]=s.top().id;
}
node nex;
nex.id=i-1;
nex.w=d[i];
s.push(nex);
//cout<<i<<" "<<r[i]<<endl;
}
while(m--)
{
long long ans=0;
long long x,y;
scanf("%lld%lld",&x,&y);
for(int i=x;i<y;i++)
{
long long tl=max(l[i],x-1);
long long tr=min(r[i],y-1);
long long num=(long long)(i-tl)*(tr-i+1);
ans+=num*d[i];
}
printf("%lld\n",ans);
}
}
}