zoukankan      html  css  js  c++  java
  • hdu 5381 The sum of gcd

    题目链接

    http://acm.hdu.edu.cn/showproblem.php?pid=5381

    题意

    给你(n)个数,(q)次查询,每次询问(l,r),输出(f(l,r)=sum_{i=l}^rsum_{j=i}^rgcd(a_i,a_{i+1},...,a_r))

    思路

    首先对于任意一个(a[i]),每次(gcd)减小至少一半,所以它向后的(gcd)最多下降(log(a[i]))次,可以求出对于每一个(a[i])来说的(gcd)相同的各个区间。
    用线段树维护一段区间的(gcd),可以查询一段([l,r])(gcd)的值(x),从(i)开始枚举左边界(l),然后用二分查找到(gcd)相同的区间的右边界(r),这个就得到了对于(a[i])来说的一段(gcd)相同的区间,而且下一个区间的左边界就成了(r+1)(gcd)值也变成(gcd(x,a[r+1])),继续二分查找该(gcd)的右边界,一直到找到第(n)个数为止。这样就得到了从(i)开始的(gcd)相同的各个区间。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxx = 10010;
    struct node{int l,r,x;};
    vector<node>v[maxx]; //保存从i开始的gcd相同的各个区间
    struct Q
    {
        int l,r,id;
        bool operator < (const Q &t)const
        {
            return l>t.l;
        }
    }q[maxx];
    int a[maxx],n,m;
    int t[maxx<<2];
    LL ans[maxx];
    struct tree
    {
        LL t[maxx<<2],lazy[maxx<<2];
        void build(int l,int r,int rt)
        {
            t[rt]=lazy[rt]=0;
            if(l==r)return;
            int mid=(l+r)/2;
            build(l,mid,rt*2);
            build(mid+1,r,rt*2+1);
        }
        void pushdown(int l,int r,int rt)
        {
            if(lazy[rt])
            {
                t[rt*2]+=lazy[rt]*l;
                t[rt*2+1]+=lazy[rt]*r;
                lazy[rt*2]+=lazy[rt];
                lazy[rt*2+1]+=lazy[rt];
                lazy[rt]=0;
            }
        }
        void update(int l,int r,int p,int q,int c,int rt)
        {
            if(p<=l&&r<=q)
            {
                t[rt]+=1LL*(r-l+1)*c;
                lazy[rt]+=c;
                return;
            }
            int mid=(l+r)/2;
            pushdown(mid-l+1,r-mid,rt);
            if(p<=mid)update(l,mid,p,q,c,rt*2);
            if(q>mid)update(mid+1,r,p,q,c,rt*2+1);
            t[rt]=t[rt*2]+t[rt*2+1];
        }
        LL query(int l,int r,int p,int q,int rt)
        {
            if(p==l&&q==r)return t[rt];
            int mid=(l+r)/2;
            pushdown(mid-l+1,r-mid,rt);
            if(q<=mid)return query(l,mid,p,q,rt*2);
            else if(p>mid)return query(mid+1,r,p,q,rt*2+1);
            else return query(l,mid,p,mid,rt*2)+query(mid+1,r,mid+1,q,rt*2+1);
        }
    }bt;
    int gcd(int a,int b)
    {
        return b==0?a:gcd(b,a%b);
    }
    void build(int l,int r,int rt)
    {
        if(l==r)
        {
            t[rt]=a[l];
            return;
        }
        int mid=(l+r)/2;
        build(l,mid,rt*2);
        build(mid+1,r,rt*2+1);
        t[rt]=gcd(t[rt*2],t[rt*2+1]);
    }
    int query(int l,int r,int p,int q,int rt)
    {
        if(l==p&&r==q)return t[rt];
        int mid=(l+r)/2;
        if(q<=mid)return query(l,mid,p,q,rt*2);
        else if(p>mid)return query(mid+1,r,p,q,rt*2+1);
        else return gcd(query(l,mid,p,mid,rt*2),query(mid+1,r,mid+1,q,rt*2+1));
    }
    int Search(int a,int b,int x)
    {
        int l=a,r=b,ans;
        while(l<=r)
        {
            int mid=(l+r)/2;
            if(query(1,n,a,mid,1)>=x)l=mid+1,ans=mid;
            else r=mid-1;
        }
        return ans;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]);
            build(1,n,1);
            node tmp;
            for(int i=1;i<=n;i++)
            {
                v[i].clear();
                int l=i,r,x=a[i];
                while(l<=n)
                {
                    r=Search(i,n,x);
                    tmp=node{l,r,x};
                    v[i].push_back(tmp);
                    x=gcd(x,a[r+1]);
                    l=r+1;
                }
            }
            scanf("%d",&m);
            for(int i=1;i<=m;i++)
                scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
            sort(q+1,q+1+m);
            bt.build(1,n,1);
            int l=n;
            for(int i=1;i<=m;i++)
            {
                while(l>=q[i].l)
                {
                    for(int j=0;j<v[l].size();j++)
                        bt.update(1,n,v[l][j].l,v[l][j].r,v[l][j].x,1);
                    l--;
                }
                ans[q[i].id]=bt.query(1,n,q[i].l,q[i].r,1);
            }
            for(int i=1;i<=m;i++)
                printf("%lld
    ",ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    利用模板实现c++智能指针
    movit 相关函数(二)
    moveit相关函数解释
    ros常用函数(1)
    Qtcreator中cin函数无法在application output中进行输入的问题的解决
    c++速成,适合有c基础的朋友(3)
    【重要通知】本博客不再更新,更多教程请访问 makermaker.cc
    BBC micro:bit 学习资源汇总(最近更新2019年1月6日....)
    [20个项目学会BBC micro:bit编程] 20-无线通信
    [20个项目学会BBC micro:bit编程] 19-直流电机控制
  • 原文地址:https://www.cnblogs.com/HooYing/p/12651319.html
Copyright © 2011-2022 走看看