UOJ Logo qx的博客

博客

数据结构

2023-11-30 18:15:16 By qx

ST

像某个 Cbh 一样 st 表都不会写还是不好的。所以写一篇 st 表。

ST 表支持维护区间问题,并且要求静态。可以达到预处理 O(nlogn),而单词查询 O(1) 的恐怖效率。空间复杂度 O(nlogn) ,想比于线段树其应用范围稍显狭窄。

But... ST 的单词查询是 O(1) 的。

下面主要以 min 操作为例介绍

ST 的思想主要基于倍增。

先要 Init(log2) 当然如果你不嫌弃 C++ 的大常数 log2 的话也不是不行。

只需要 Init([1n])log2 就好了。这一步主要是为了应付后面倍增要求。显然,log2(x)=log2([x2])+1 理由不想多说。按照这个步骤初始化即可。

STEP.1

然后就是预处理。可以得到一个 min 特有的关系式,大概就是这个相貌:

mini=lra[i]=min{mini=lkra[i],minklra[i]}

等式右边的两项可以通过刚刚的方法求得。

这样就可以开始推导推导了:设 dp[i][j] 表示 mink=ll+2ja[k],这里就可以出来一个转移方程:

dp[i][j]=min{dp[i][j1],dp[i+2j1][j1]}

理由如上。

STEP.2

查询操作。

mini=lra[i]=min{dp[l][k],dp[r2k][k]}

其中 k=log2(rl+1)

理由还是如上。

STEP.3

吸取了某个叫 CBH 同学的教训,我们可以知道 k 就是 k ,不要 k1.

上代码。

// here is Init
void init(){
    lg[0]=-1;
    FOR(i,1,n) lg[i]=lg[i>>1]+1;
    FOR(i,1,n) dp[i][0]=a[i];
    int lim=lg[n];
    FOR(k,1,lim)
        FOR(s,1,n+1-(1<<k))
            dp[s][k]=max(dp[s][k-1],dp[s+(1<<(k-1))][k-1]);
}
// here is Query
l=read();r=read();
int k=lg[r-l+1];
cout<<max(dp[l][k],dp[r-(1<<k)+1][k])<<'\n';

那么除了 min 之外 ST 还可以维护 GCD,MAX,OR,LCM 之类的东西。

O(nlogn)+O(nlogn)+O(1)

评论

什么个鬼?

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。