百度之星初赛第三场6

  • 题目: 区间最大值
  • 思路: (看别人的题解 单调栈 + 倍增 + 前缀) 因为学习倍增还是还是关于树上倍增导致思维僵硬,对于倍增算法的其他类型应用就不会融会贯通 这道题很好的锻炼了我这一方面的缺陷
    首先是两个数组 fa[i][j]来记录下标 i 向右走 2 j的最大值所在的段
    dis[i][j]记录下标 i 向右走 2 j的所做的贡献
    先来一个单调栈来预处理一下所有的 fa[i][0] dis[i][0],然后再进行倍增算法,处理结束以后读入查询 最后一段再额外加上去
    代码:
#include <bits/stdc++.h>
#define int long long 
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int>
using namespace std;

const int N = 2e5 + 100,M = N * 2,INF = 0x3f3f3f3f;
int a[N],s[N];
stack<int> d;
int fa[N][20],dis[N][20];
void solve()
{
    int n,q; cin >> n >> q;
    for(int i = 1;i <= n;i ++ ) cin >> a[i],s[i] = s[i - 1] + a[i];
    
    for(int i = n;i >= 1;i -- )
    {
        while(d.size() && a[d.top()] < a[i]) d.pop();
        if(!d.size()) fa[i][0] = n + 1;
        else fa[i][0] = d.top();
        
        d.push(i);
    }
    
    for(int i = 1;i <= n;i ++ )
    {
        int vis = s[fa[i][0] - 1] - s[i - 1];
        dis[i][0] = a[i] * vis;
    }
    
    for(int j = 1;j <= 19;j ++ )
    {
        for(int i = 1;i <= n;i ++ )
        {
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
            dis[i][j] = dis[i][j - 1] + dis[fa[i][j - 1]][j - 1];
        }
    }
    
    while(q -- )
    {
        int l,r; cin >> l >> r;
        int p = l;
        int ans = 0;
        for(int i = 19;i >= 0;i -- )
        {
            if(fa[p][i] <= r && fa[p][i])
            {
                ans += dis[p][i];
                p = fa[p][i];
            }
        }
        ans += a[p] * (s[r] - s[p - 1]);
        cout << ans << endl;
    }
}

signed main()
{
    ios;int T = 1; while(T -- ) solve();
    return 0;
}
``
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值