「杂题乱刷2」CF601B
怎么没人写好写的 ST 表呢。
题目链接
CF601B Lipshitz Sequence (luogu)
CF601B Lipshitz Sequence (codeforces)
解题思路
其实一眼可以发现选相邻的是最优的。
证明:
若这个区间中的数字为 \([a,b,c]\),此时若选择 \(a,c\) 这两个数字,则必有 \(\frac{|a - c|}{2} \ge |a - b|\),\(\frac{|a-c|}{2} \ge |b - c|\),两式相加得 \(|a - c| \ge |a - b| + |b - c|\),此时分讨三个数的大小关系:
-
\(a \le b \le c\),此时式子为 \(c - a \ge b - a + c - b\),化简得 \(0 \ge 0\),说明此时选相邻两个数与选 \(a,c\) 两个数相比不劣。
-
\(a \le c \le b\),此时式子为 \(c - a \ge b - a + b - c\),化简得 \(2c \ge 2b\),由于 \(c \le b\),因此 \(2c \le b\),不符合原命题,说明此时选相邻两个数与选 \(a,c\) 两个数相比不劣。
-
\(b \le a \le c\),此时式子为 \(c - a \ge a - b + c - b\),化简得 \(2b \ge 2a\),由于 \(b \le a\),因此 \(2b \le 2a\),不符合原命题,说明此时选相邻两个数与选 \(a,c\) 两个数相比不劣。
-
\(b \le c \le a\),此时式子为 \(a - c \ge a - b + c - b\),化简得 \(2b \ge 2c\),由于 \(b \le c\),因此 \(2b \le 2c\),不符合原命题,说明此时选相邻两个数与选 \(a,c\) 两个数相比不劣。
-
\(c \le a \le b\),此时式子为 \(a - c \ge b - a + b - c\),化简得 \(2a \ge 2b\),由于 \(a \le b\),因此 \(2a \le 2b\),不符合原命题,说明此时选相邻两个数与选 \(a,c\) 两个数相比不劣。
-
\(c \le b \le a\),此时式子为 \(a - c \ge a - b + b - c\),化简得 \(0 \ge 0\),说明此时选相邻两个数与选 \(a,c\) 两个数相比不劣。
因此选相邻两个数字一定不劣,此时设 \(i \in [1,n-1]\),\(b_i = |a_i - a_{i+1}|\),则答案为 \(\sum_{i=l}^{r-1} \sum_{j=i}^{r-1} \max_{k=i}^{j} b_k\)。
这是一个经典的问题,直接 ST 表加二分即可,注意此时需要预处理每个 \(L,R\) 的节点,这样复杂度是 \(O(n \log n + nq)\) 的,不会 TLE,否则直接做是 \(O(qn \log n)\) 的,会 TLE。
直接单调栈也能做,我写的是 ST 表。
参考代码
#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll int
#define forl(i,a,b) for(re ll (i)=(a);i<=(b);(i)++)
#define forr(i,a,b) for(re ll (i)=(a);i>=(b);(i)--)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
#define QwQ return 0;
ll pw(ll x){return 1ll<<x;}
ll _t_;
ll lg[1000110];
void Init(){
forl(i,2,1e6+5)
lg[i]=lg[i>>1]+1;
}
ll n,q;
ll a[100010];
ll b[100010];
ll l,r;
ll maxn[100010][20];
ll nL[100010],nR[100010];
ll query(ll l,ll r)
{
if(l>r)
return (ll)2e9;
ll LG=lg[r-l+1];
return max(maxn[l][LG],maxn[r-pw(LG)+1][LG]);
}
long long ans;
void _clear(){}
void solve()
{
_clear();
cin>>n>>q;
forl(i,1,n)
cin>>a[i];
forl(i,1,n-1)
b[i]=abs(a[i+1]-a[i]),
maxn[i][0]=b[i];
n--;
forl(j,1,19)
forl(i,1,n-pw(j)+1)
maxn[i][j]=max(maxn[i][j-1],maxn[i+pw(j-1)][j-1]);
l=1,r=n;
ans=0;
forl(i,l,r)
{
ll L=l,R=i;
while(L<R)
{
ll Mid=(L+R)/2;
if(query(Mid,i-1)<b[i])
R=Mid;
else
L=Mid+1;
}
ll nl=L;
L=i,R=r;
while(L<R)
{
ll Mid=(L+R+1)/2;
if(query(i+1,Mid)<=b[i])
L=Mid;
else
R=Mid-1;
}
ll nr=L;
if(query(nl,i)==b[i] && query(i,nr)==b[i])
nL[i]=nl,
nR[i]=nr;
else
nL[i]=nR[i]=i;
}
while(q--)
{
cin>>l>>r;
r--;
forl(i,l,r)
{
ll nl=max(nL[i],l),nr=min(nR[i],r);
ans+=1ll*b[i]*(i-nl+1)*(nr-i+1);
}
cout<<ans<<endl;
ans=0;
}
}
int main()
{
Init();
IOS;
_t_=1;
while(_t_--)
solve();
QwQ;
}

浙公网安备 33010602011771号