倍增与分治

ST表

可用于求解区间最大、最小值、GCD、LCM及满足相应性质的区间运算:算子满足区间可加性。

以求解区间最大值为例:

\(ST_{i,j}\)表示从下标\(i\)开始的长度为\(2^i\)的区间最大值,初始化\(ST_{i,0}=a_i\)

构建\(ST\)表时,有\(ST_{j,i}=\max(ST_{j,i-1},ST_{j+2^i-1,i-1})\)

求解询问\([L,R]\)时,计算区间\(k=\log_2\lfloor R-L+1\rfloor\)\(ans=\max(ST_{L,k},ST_{R-2^k+1,k})\)

【倍增】Luogu P1890 区间GCD

给出序列\(A=\left \{a_1,a_2,\cdots,a_n \right \}\)\(q\)个询问,每个询问包含\(L,R\)两个参数,求\(gcd(a_L,a_{L+1},\cdots,a_{R-1},a_R)\)

参考解答
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int lg[N],st[N][20],n,q,ans;
int gcd(int x,int y)
{
    if(!y) return x;
    return gcd(y,x%y); 
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&st[i][0]);
    for(int i=2;i<=n;i++) lg[i]=lg[i/2]+1;
    for(int j=1;j<=lg[n];j++)
    {
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=gcd(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    }
    int x,y;
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&x,&y);
        int len=lg[y-x+1];
        ans=gcd(st[x][len],st[y-(1<<len)+1][len]);
        printf("%d\n",ans);
    }
    return 0;
}