zoukankan      html  css  js  c++  java
  • 树状数组区间更新区间查询以及gcd的logn性质

    题目描述

    给你一个长为n的序列a

    m次查询

    每次查询一个区间的所有子区间的gcd的和mod1e9+7的结果

    输入描述:

    第一行两个数n,m
    之后一行n个数表示a
    之后m行每行两个数l,r表示查询的区间

    输出描述:

    对于每个询问,输出一行一个数表示答案
    示例1

    输入

    5 7
    30 60 20 20 20
    1 1
    1 5
    2 4
    3 4
    3 5
    2 5
    2 3

    输出

    30
    330
    160
    60
    120
    240
    100

    说明

    [1,1]的子区间只有[1,1],其gcd为30
    [1,5]的子区间有:
    [1,1]=30,[1,2]=30,[1,3]=10,[1,4]=10,[1,5]=10
    [2,2]=60,[2,3]=20,[2,4]=20,[2,5]=20
    [3,3]=20,[3,4]=20,[3,5]=20
    [4,4]=20,[4,5]=20
    [5,5]=20
    总共330
    [2,4]的子区间有:
    [2,2]=60,[2,3]=20,[2,4]=20
    [3,3]=20,[3,4]=20
    [4,4]=20
    总共160
    [3,4]的子区间有:
    [3,3]=20,[3,4]=20
    [4,4]=20
    总共60
    [3,5]的子区间有:
    [3,3]=20,[3,4]=20,[3,5]=20
    [4,4]=20,[4,5]=20
    [5,5]=20
    总共120
    [2,5]的子区间有:
    [2,2]=60,[2,3]=20,[2,4]=20,[2,5]=20
    [3,3]=20,[3,4]=20,[3,5]=20
    [4,4]=20,[4,5]=20
    [5,5]=20
    总共240
    [2,3]的子区间有:
    [2,2]=60,[2,3]=20
    [3,3]=20
    总共100

    http://blog.csdn.net/fsahfgsadhsakndas/article/details/52650026 //详解

    我们假设sigma(r,i)表示r数组的前i项和,调用一次的复杂度是log2(i)

    设原数组是a[n],差分数组c[n],c[i]=a[i]-a[i-1],那么明显地a[i]=sigma(c,i),如果想要修改a[i]到a[j](比如+v),只需令c[i]+=v,c[j+1]-=v

    【今天的主要内容】

    我们可以实现NlogN时间的“单点修改,区间查询”,“区间修改,单点查询”,其实后者就是前者的一个变形,要明白树状数组的本质就是“单点修改,区间查询”

    怎么实现“区间修改,区间查询”呢?

    观察式子:
    a[1]+a[2]+...+a[n]

    = (c[1]) + (c[1]+c[2]) + ... + (c[1]+c[2]+...+c[n]) 

    = n*c[1] + (n-1)*c[2] +... +c[n]

    = n * (c[1]+c[2]+...+c[n]) - (0*c[1]+1*c[2]+...+(n-1)*c[n])    (式子①)

    那么我们就维护一个数组c2[n],其中c2[i] = (i-1)*c[i]

    每当修改c的时候,就同步修改一下c2,这样复杂度就不会改变

    那么

    式子①

    =n*sigma(c,n) - sigma(c2,n)



    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+88;
    const int mod=1e9+7;
    int n,m,a[N],v[250],pos[250];
    long long f[N],g[N],ans[N];
    struct node{
        int l,r,id;
        bool operator < (const node &A)const{
        return r<A.r;
        }
    }q[N];
    void add(int x,int y){
        for(int i=x;i<=n;i+=i&(-i)) f[i]+=y,g[i]+=1LL*(x-1)*y;
    }
    long long query(int u){
        long long ans=0;
        for(int i=u;i;i-=i&(-i)) ans=(ans+1LL*u*f[i]-g[i])%mod;
        return ans;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) scanf("%d",a+i);
        for(int i=1;i<=m;++i) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
        sort(q+1,q+m+1);
        int tot=0,now;
        for(int i=1,p=1;i<=m;++i) {
            while(p<=q[i].r) {
                for(int j=1;j<=tot;++j) v[j]=__gcd(v[j],a[p]);
                v[++tot]=a[p],pos[tot]=p;
                now=tot,tot=0;
                for(int j=1;j<=now;++j) if(v[j]!=v[j-1]) v[++tot]=v[j],pos[tot]=pos[j];
                for(int j=1;j<tot;++j) add(pos[j],v[j]),add(pos[j+1],-v[j]);
                add(pos[tot],v[tot]),add(p+1,-v[tot]);
                ++p;
            }
            ans[q[i].id]=query(q[i].r)-query(q[i].l-1);
        }
        for(int i=1;i<=m;++i) printf("%lld
    ",(ans[i]+mod)%mod);
    } 
  • 相关阅读:
    Apache Commons Fileupload 反序列化漏洞分析
    Linux下安装python3.6
    使用salt-stack指定IP添加系统用户为root的权限
    virt-install创建虚拟机并制作成模板
    virsh console 登录CentOS7系统
    Cobbler本机使用VM装机配置方法
    Cobbler自动化部署
    调用python脚本报错/usr/bin/env: python : No such file or directory
    启动keepalived报错(VI_1): received an invalid passwd!
    rsync+sersync实现数据实时同步
  • 原文地址:https://www.cnblogs.com/mfys/p/8228132.html
Copyright © 2011-2022 走看看