[模板] 动态ST表

本文介绍了一种利用ST表进行快速区间查询的方法,并通过逆向思维实现动态更新。通过实例代码展示了如何在不直接修改ST表的前提下,高效地处理新增元素,确保查询效率的同时降低常数开销。

ST表本身是不可修改的。

如果考虑增加一个数,可以把ST表反过来写,即f[i][j]表示i往前1<<j个数,一个数最多影响logn个数,常数非常小。

 

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;

const int MAXN=200005;

typedef long long ll;

inline ll rd(){
    ll ret=0,f=1;char c;
    while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
    while(isdigit(c))ret=ret*10+c-'0',c=getchar();
    return ret*f;
}

ll f[MAXN][32];
ll m,mod;
int p;

int main(){
    m=rd();mod=rd();
    char s[5];ll x,t=0;
    while(m--){
        scanf("%s",s);x=rd();
        if(s[0]=='Q') {
            int len=log2(x);
            printf("%lld\n",t=max(f[p][len],f[p-x+(1<<len)][len])%mod);
        }else{
            f[++p][0]=(x+t)%mod;
            for(int i=1;p-(1<<i)>=0;i++) f[p][i]=max(f[p][i-1],f[p-(1<<(i-1))][i-1]);
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ghostcai/p/9291670.html

ST是一种用于快速查询区间值的据结构。它的核心思想是对区间进行预处理,将区间内的值信息存储在一个二维组中,然后利用这个组进行查询。以下是一个大值的ST模板代码: ``` const int MAXN = 100005; const int MAXLOGN = 20; int a[MAXN]; int st[MAXN][MAXLOGN]; void init(int n) { for (int i = 1; i <= n; i++) { st[i][0] = a[i]; } for (int j = 1; (1 << j) <= n; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) { st[i][j] = max(st[i][j-1], st[i+(1<<(j-1))][j-1]); } } } int query(int l, int r) { int k = log2(r-l+1); // k为大的2的幂次方,使得2^k <= r-l+1 return max(st[l][k], st[r-(1<<k)+1][k]); } int main() { int n, q; cin >> n >> q; for (int i = 1; i <= n; i++) { cin >> a[i]; } init(n); while (q--) { int l, r; cin >> l >> r; cout << query(l, r) << endl; } return 0; } ``` 这段代码中,init函用于初始化ST,query函用于查询区间大值。具体来说,init函的实现如下: 1. 将a[i]的值存储到st[i][0]中,示区间[i,i]的大值为a[i]。 2. 对于每个j,计算区间[i,i+2^j-1]的大值,存储在st[i][j]中。可以发现,区间[i,i+2^j-1]可以拆分为两个长度为2^(j-1)的子区间,即区间[i,i+2^(j-1)-1]和区间[i+2^(j-1),i+2^j-1]。因此,区间[i,i+2^j-1]的大值等于区间[i,i+2^(j-1)-1]的大值和区间[i+2^(j-1),i+2^j-1]的大值中较大的一个。 query函的实现也比较简单,首先计算k,然后查询区间[l,r]的大值,等价于查询区间[l,l+2^k-1]的大值和区间[r-2^k+1,r]的大值中较大的一个。 求小值的ST模板代码与求大值的类似,只需要将max改为min即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值