Boring Queries

Boring Queries

分析

关键点之一,在于我们对lcm性质的了解。n个数的lcm就等于\(LCM_{i=l}^{r}a_i=\prod_{p是质数}p^{\max_{l\leq i \leq r}}cntt_{i,p}\),其中\(cnt_{i,p}\)表示\(a_i\)p的的次数。

我们考虑根号分治。小于450的质数有87个。

下面就是一步很精妙的想法,我们先将所有\(a_i\)中的小于450的质因子全部除去,则剩下的一定是1或者是大于450的质数。

则我们的答案ans首先就会来自一部分在小于450的质数中,我们先把那一部分统计下来,由于我们要求区间内数字的区间最值,还是静态的,那当然用ST表来实现。我们用ST表去维护,每一个数字在某个区间出现的最大次数。

然后剩下的问题就变成了,求区间[l,r]中出现过的数字的乘积(相同的只算一次)。粘上去重我们一般都考虑能否离线,但是这题强制在线。如果不能离线,那这类问题我们通常用主席树去做。我们来看看怎么用主席树去做。

首先,我们设\(pre_i\)表示[1,i-1]\(a_i\)最后一次出现的位置,没有出现则为0。这个可以\(O(n)\)求到。

对于一个\(i(l \leq i \leq r)\),若\(l \leq pre_i\),说明[l,i-1]中出现了一个与\(a_i\)相等的数,那么这个i是不能算贡献的。

问题就又变成了,\(\prod_{i=l}^{r}[pre_i \leq l - 1]a_i\)。考虑建立主席树,第j棵树维护的是\(pre_i \leq j\)的数的乘积。(\(peq_i>j\)的位置上都为1)。

我们需要做的是,对于某个值\(a_i\),如果是第一次出现,我们直接在root[0]的位置进行修改。否则,我们设\(b_i\)表示为下一个与\(a_i\)相同的位置是哪,我们到这个位置后,直接新建一棵树,直接单点修\(b_i\),该位置改为\(a_{b_i}\)

简单来说,我们是用这种方式,用空间把所有情况预处理出来了。所有的本可以离线但强制在线的题目都是类似的思路。

看看代码。

AC_code

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;
using ll = long long;
const int N = 2e5 + 10,SQRT = 450,mod = 1e9 + 7;
struct Node
{
    int l,r;
    ll prod;
}tr[N*20];

int n,a[N],b[N],rt[N],idx,lg[N],primes[SQRT],pos[N],cnt;
bool ispri[SQRT];
char st[90][N][18];
ll poww[100][20];

void get_primes()
{
    ispri[1] = 1;
    for(int i=2;i<=SQRT-1;i++)
    {
        if(!ispri[i]) primes[++cnt] = i;
        for(int j=1;primes[j]*i<=SQRT-1;j++)
        {
            ispri[primes[j]*i] = 1;
            if(i%primes[j]==0) break;
        }
    }
}

void pushup(int u)
{
    tr[u].prod = tr[tr[u].l].prod * tr[tr[u].r].prod % mod;
}

int query(int u,int l,int r)
{
    int p = lg[r - l + 1];
    return max(st[u][l][p],st[u][r-(1<<p)+1][p]);
}

void modify1(int &u,int l,int r,int x,int y)
{
    if(l==r)
    {
        tr[u].prod = y;
        return ;
    }
    int mid = l + r >> 1;
    if(x<=mid) modify1(tr[u].l,l,mid,x,y);
    else modify1(tr[u].r,mid+1,r,x,y);
    pushup(u);
}

void modify2(int u,int &v,int l,int r,int x,int y)
{
    v = ++idx;
    tr[v] = tr[u];
    if(l==r)
    {
        tr[v].prod = y;
        return ;
    }
    int mid = l + r >> 1;
    if(x<=mid) modify2(tr[u].l,tr[v].l,l,mid,x,y);
    else modify2(tr[u].r,tr[v].r,mid+1,r,x,y);
    pushup(v);
}

ll query(int u,int l,int r,int x,int y)
{
    if(l>y||r<x) return 1;
    if(!u) return 1;
    if(x<=l&&r<=y) return tr[u].prod;
    int mid = l + r >> 1;
    return query(tr[u].l,l,mid,x,y) * query(tr[u].r,mid+1,r,x,y) % mod;
}

void build(int &u,int l,int r)
{
    u = ++idx;
    if(l==r)
    {
        tr[u].prod = 1;
        return ;
    }
    int mid = l + r >> 1;
    build(tr[u].l,l,mid),build(tr[u].r,mid+1,r);
    pushup(u);
}

void buildst()
{
    for(int i=2;i<=n;i++) lg[i] = lg[i/2] + 1;
    for(int k=1;k<=cnt;k++) 
        for(int j=1;j<=lg[n];j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                st[k][i][j] = max(st[k][i][j-1],st[k][i+(1<<j-1)][j-1]);
}

void buildseg()
{
    build(rt[0],1,n);
    for(int i=1;i<=n;i++)
    {
        if(!pos[a[i]]) modify1(rt[0],1,n,i,a[i]);
        else b[pos[a[i]]] = i;
        pos[a[i]] = i;
    }
    for(int i=1;i<=n;i++)
    {
        if(b[i]) modify2(rt[i-1],rt[i],1,n,b[i],a[b[i]]);
        else rt[i] = rt[i-1];
    }
}

int main()
{
    get_primes();
    ios;cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        for(int j=1;j<=cnt;j++)
            while(a[i]%primes[j]==0)
            {
                a[i]/=primes[j];
                st[j][i][0]++;
            }
    }
    buildst();
    buildseg();
    ll ans = 0;
    for(int i=1;i<=cnt;i++)
    {
        poww[i][0] = 1;
        for(int j=1;j<=20;j++) poww[i][j] = (poww[i][j-1]*primes[i])%mod;
    }
    int q;cin>>q;
    while(q--)
    {
        int x,y;cin>>x>>y;
        x = (x + ans) % n + 1;y = (y + ans) %n + 1;
        if(x>y) swap(x,y);
        ans = 1;
        for(int i=1;i<=cnt;i++) ans = ans * poww[i][query(i,x,y)] % mod;
        ans = ans * query(rt[x-1],1,n,x,y) % mod;
        cout<<ans<<'\n';
    }
    return 0;
}
posted @ 2022-11-08 23:11  艾特玖  阅读(11)  评论(0编辑  收藏  举报