• 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;
    }
  • 相关阅读:
    iOS 给Main.storyboard 添加button 事件《转》
    vs2015
    1520-win10
    [置顶] Flex中Tree组件无刷新删除节点
    数据结构(10)之查找
    oracle 在表中有数据的情况下修改表字段类型或缩小长度
    UVa123
    1000万条数据导入mysql
    Linux协议栈代码阅读笔记(二)网络接口的配置
    jquery.validate.js 应用示例
  • 原文地址:https://www.cnblogs.com/zufezzt/p/5866135.html
Copyright © 2020-2023  润新知