HDU 5869 Different GCD Subarray Query

离线操作,树状数组,$RMQ$。

这个题的本质和$HDU$ $3333$是一样的,$HDU$ $3333$要求计算区间内不同的数字有几个。

这题稍微变了一下,相当于原来扫描到$i$的之后是更新$a[i]$的情况,现在是更新$log$级别个数的数字(因为以$i$为结尾的区间,最多只有$log$级别种不同的$gcd$)。

求区间$gcd$可以用$RMQ$预处理一下,然后就可以$O(1)$查询了。

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
typedef long long LL;
const double pi=acos(-1.0),eps=1e-6;
void File()
{
    freopen("D:\in.txt","r",stdin);
    freopen("D:\out.txt","w",stdout);
}
template <class T>
inline void read(T &x)
{
    char c=getchar(); x=0;
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) {x=x*10+c-'0'; c=getchar();}
}

const int maxn=100000+10;
int T,n,Q,a[maxn],dp[maxn][30],c[maxn],pre[maxn*10],ans[maxn];
struct X{int L,R,id;}s[maxn];

int gcd(int a,int b) { if(b==0) return a; return gcd(b,a%b); }

void RMQ_init()
{
    for(int i=0;i<n;i++) dp[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=0;i+(1<<j)-1<n;i++)
            dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}

int RMQ(int L,int R)
{
    int k=0;
    while((1<<(k+1))<=R-L+1) k++;
    return gcd(dp[L][k],dp[R-(1<<k)+1][k]);
}

bool cmp (X a,X b) { return a.R<b.R; }

int lowbit(int x) {return x&(-x);}
int sum(int x)
{
    int res=0;
    for(int i=x;i>0;i=i-lowbit(i)) res=res+c[i];
    return res;
}
void update(int x,int v)
{
    for(int i=x;i<=n;i=i+lowbit(i)) c[i]=c[i]+v;
}

int main()
{
    while(~scanf("%d%d",&n,&Q))
    {
        for(int i=0;i<n;i++) scanf("%d",&a[i]);
        RMQ_init();

        for(int i=0;i<Q;i++) scanf("%d%d",&s[i].L,&s[i].R),s[i].id=i;
        sort(s,s+Q,cmp);

        memset(pre,0,sizeof pre); memset(c,0,sizeof c); int p=0;
        for(int i=0;i<n;i++)
        {
            int L=0,R=i,g=a[i];

            while(1)
            {
                int left=L,right=R,pos1,pos2;

                while(left<=right)
                {
                    int mid=(left+right)/2;
                    if(RMQ(mid,i)==g) pos1=mid,right=mid-1;
                    else left=mid+1;
                }

                left=L,right=R,pos2;
                while(left<=right)
                {
                    int mid=(left+right)/2;
                    if(RMQ(mid,i)==g) pos2=mid,left=mid+1;
                    else left=mid+1;
                }

                pos1++,pos2++;
                if(pre[g]>pos2) continue;
                if(pre[g]!=0) update(pre[g],-1);
                update(pos2,1); pre[g]=pos2;
                pos1--,pos2--;

                R=pos1-1;  if(R<0) break; g=RMQ(R,i);
            }

            while(p<Q&&s[p].R==i+1)
                ans[s[p].id]=sum(s[p].R)-sum(s[p].L-1), p++;
        }

        for(int i=0;i<Q;i++) printf("%d
",ans[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zufezzt/p/5866135.html