「杂题乱刷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;
}
posted @ 2025-01-28 16:01  wangmarui  阅读(14)  评论(0)    收藏  举报