ST表及RMQ例题

ST表

主要是RMQ的工具,可以查找最大值或者最小值。复杂度为NlogN预处理,O(1)查询。

线段树查询最大值或者最小值预处理O(n),查询O(log)。

思想

倍增的思想。

先处理出所有长度为1的最小值,再处理出长度为2的最小值,然后是4,8,16······。

用f[i][j]表示长度为2的j次方第i个位置上的最小值。

有递推公式:f[j][i]=min(f[j][i-1],f[j+2i-1][i-1])。

根据计算机组成原理,数组大访问的时间开销也较大。[22][1e6]的开销小于[1e6][22]的开销。

for(int j=1;j<=20;j++) {
        for(int i=1;i+(1<<j)-1<=n;i++) {
            f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]);
        }
    }
    lg[1]=0; // 对log2取上整的预处理
    for(int i=2;i<=n;i++) {
        lg[i]=lg[i>>1]+1;
    }
// 也可以直接用std::__lg();

拓展

可以维护一些一个数和自己做运算结果相同的操作。除了min,max之外还有&,|,gcd。局限性:不可修改,只可查。

题目描述

给nn个数a1,a2,…,ana1,a2,…,an,qq个询问。

每个询问给定两个数l,rl,r,求出al,al+1,…,aral,al+1,…,ar中的最大值。

输入格式

第一行五个数n,q,A,B,C(1≤n≤106,1≤q≤107,0≤A,B,C<232)n,q,A,B,C(1≤n≤106,1≤q≤107,0≤A,B,C<232)。

为了防止输入过大,aiai和询问用下面代码生成。

unsigned int A, B, C;
inline unsigned int rng61() {
    A ^= A << 16;
    A ^= A >> 5;
    A ^= A << 1;
    unsigned int t = A;
    A = B;
    B = C;
    C ^= t ^ A;
    return C;
}
int main(){
    scanf("%d%d%u%u%u", &n, &q, &A, &B, &C);
    for (int i = 1; i <= n; i++) {
        a[i] = rng61();
    }
    for (int i = 1; i <= q; i++) {
        unsigned int l = rng61() % n + 1, r = rng61() % n + 1;
        if (l > r) swap(l, r);
    }
}

思路

板子题。注意优化。

ll 改成unsigned int 时间只用了一半,可见long long有时候会被卡常。

int __builtin_clz (unsigned int x) 的作用是:Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.补:x=0得到的是31,x=10是27.这个函数效率也高,比用数组向后推快了不少,这个可以快速得到log2X向下取整的值。

#include <bits/stdc++.h>
typedef long long ll;
#define pb push_back
#define pob pop_back
#define mem(a,b) memset(a,b,sizeof(a))
#define all(a) (a).begin(),(a).end()
#define debug(a) cout<<#a<<"="<<a<<endl;
inline ll rr(){ll f=1,x=0;char ch;do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');return f*x;}
using namespace std;
const ll INF=0x3f3f3f3f,inf=0x3f3f3f3f3f3f3f;
const int maxn=1e6+6;

unsigned int a[maxn],n,q,f[22][maxn],lg[maxn];
unsigned int A, B, C;
inline unsigned int rng61() {
    A ^= A << 16;
    A ^= A >> 5;
    A ^= A << 1;
    unsigned int t = A;
    A = B;
    B = C;
    C ^= t ^ A;
    return C;
}
int main(){
    scanf("%d%d%u%u%u", &n, &q, &A, &B, &C);
    for (int i = 1; i <= n; i++) {
        a[i] = rng61();
        f[0][i]=a[i];
    }
    for(int j=1;j<=20;j++) {
        for(int i=1;i+(1<<j)-1<=n;i++) {
            f[j][i]=max(f[j-1][i],f[j-1][i+(1<<(j-1))]);
        }
    }
    ll ans=0;
    for (int i = 1; i <= q; i++) {
        unsigned int l = rng61() % n + 1, r = rng61() % n + 1;
        if (l > r) swap(l, r);
        int len=31-__builtin_clz(r-l+1);
        ans^=max(f[len][l],f[len][r-(1<<len)+1]);
    }
    std::cout << ans << '\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值