1273. 天才的记忆 RMQ ST表 线段树

题目

在这里插入图片描述

题解思路

ST表 做法

在这里插入图片描述
定义一个方程 来表示从i开始长度为2的 j 次方的区间 中的最大值

转移方程如上 。

这样我们就可以O1的查询最大值了。

在 l 到 R的区间中 必然存在一个2的幂次 K 让 2的幂次 k+1大于区间长度 K小于长度

这样就能夹出最大值了。

线段树做法

改一下sum就成了

经典 只有查询的线段树

AC代码

ST表代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
using namespace std;

const  int  INF =  0x3f3f3f3f;


long long  f[200100][110] ;
long long  a[200100] ;
int n;


int main ()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for (int i = 1 ; i <= n ; i++ )
        cin>>a[i];
    for (int j = 0 ;  j < 18 ; j++ )
    {
        for (int i = 1 ; i + (1 << j ) - 1 <= n ; i++ )
        {
            if ( !j )
                f[i][j] = a[i];
            else
                f[i][j] = max( f[i][j-1] , f[i+ (1<<j-1)][j-1] );
        }
    }

    int m;
    cin>>m;
    while(m--)
    {
        int t1,t2;
        cin>>t1>>t2;
        int len = t2 - t1 + 1;
        int k = log(len)/log(2);  //换底
        cout<< max(f[t1][k] , f[t2-(1<<k)+1][k] ) <<"\n";
    }

    return 0 ;
}

线段树代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
using namespace std;

const  int  INF =  0x3f3f3f3f;

struct node
{
    long long sum;
    int l,r,lz;
};
const int N = 1001000 ;
long long a[N];
node tee[2*N];

int n;

void  in(int i , int t1 , int t2)
{
    tee[i].l = t1 , tee[i].r = t2;
    if ( t1 == t2 )
    {
        tee[i].sum = a[t1];
        tee[i].lz = 0 ;
        return ;
    }
    int j = (t1+t2)/2;
    in(i*2,t1,j);
    in(i*2+1,j+1,t2);
    tee[i].sum = max(tee[i*2].sum, tee[i*2+1].sum );
    tee[i].lz = 0 ;
}
void pd(int i )
{
    if ( tee[i].lz != 0 )
    {
        tee[i*2].lz += tee[i].lz;
        tee[i*2+1].lz += tee[i].lz;
        tee[i*2].sum += tee[i].lz*(tee[i*2].r - tee[i*2].l + 1 );
        tee[i*2+1].sum += tee[i].lz*(tee[i*2+1].r - tee[i*2+1].l + 1 );
        tee[i].lz = 0 ;
    }
}
long long sea( int i ,int t1 , int t2 )
{
    if ( tee[i].l >= t1 && tee[i].r <= t2 )
        return tee[i].sum;
    pd(i);
    long long sum = -1000000;
    if ( tee[i*2].r >= t1 )
        sum = max(sea(i*2,t1,t2) , sum );
    if ( tee[i*2+1].l <= t2 )
        sum = max(sea(i*2+1,t1,t2), sum) ;
    return sum;
}
void _add( int i , int t1 , int t2 , int vv )
{
    if ( tee[i].l >= t1 && tee[i].r <= t2 )
    {
         tee[i].sum += vv*(tee[i].r - tee[i].l + 1);
         tee[i].lz += vv ;
         return;
    }
    pd(i);
    if ( tee[i*2].r >= t1)
        _add(i*2,t1,t2,vv);
    if (tee[i*2+1].l <= t2)
        _add(i*2+1,t1,t2,vv);
    tee[i].sum = tee[i*2].sum + tee[i*2+1].sum;

}
int main ()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for (int i = 1 ; i <= n ; i++ )
        cin>>a[i];
    in(1,1,n);
    int m;
    vector <long long > ans ;
    cin>>m;
    for (int i = 1 ; i <= m ; i++ )
    {
        int t1,t2;
        cin>>t1>>t2;
        ans.push_back( sea(1, t1,t2) );
    }
    for ( auto i : ans )
        cout<<i<<"\n";
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值