题目描述

给你一个长为n的序列a

m次查询

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

输入描述:

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

输出描述:

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

输入例子:
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

输入

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+;
const int mod=1e9+;
int n,m,a[N],v[],pos[];
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-)*y;
}
long long query(int u){
long long ans=;
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=;i<=n;++i) scanf("%d",a+i);
for(int i=;i<=m;++i) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
sort(q+,q+m+);
int tot=,now;
for(int i=,p=;i<=m;++i) {
while(p<=q[i].r) {
for(int j=;j<=tot;++j) v[j]=__gcd(v[j],a[p]);
v[++tot]=a[p],pos[tot]=p;
now=tot,tot=;
for(int j=;j<=now;++j) if(v[j]!=v[j-]) v[++tot]=v[j],pos[tot]=pos[j];
for(int j=;j<tot;++j) add(pos[j],v[j]),add(pos[j+],-v[j]);
add(pos[tot],v[tot]),add(p+,-v[tot]);
++p;
}
ans[q[i].id]=query(q[i].r)-query(q[i].l-);
}
for(int i=;i<=m;++i) printf("%lld\n",(ans[i]+mod)%mod);
}

树状数组区间更新区间查询以及gcd的logn性质的更多相关文章

  1. 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询

    题目描述 给出一棵n个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1. 定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目. 现有m次操作 ...

  2. 【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询

    题目描述 JYY有N个平面坐标系中的矩形.每一个矩形的底边都平行于X轴,侧边平行于Y轴.第i个矩形的左下角坐标为(Xi,Yi),底边长为Ai,侧边长为Bi.现在JYY打算从这N个矩形中,随机选出两个不 ...

  3. 【bzoj3132】上帝造题的七分钟 二维树状数组区间修改区间查询

    题目描述 “第一分钟,X说,要有矩阵,于是便有了一个里面写满了0的n×m矩阵. 第二分钟,L说,要能修改,于是便有了将左上角为(a,b),右下角为(c,d)的一个矩形区域内的全部数字加上一个值的操作. ...

  4. 【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改区间查询

    题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i ...

  5. hdu 2642二维树状数组 单点更新区间查询 模板题

    二维树状数组 单点更新区间查询 模板 从零开始借鉴http://www.2cto.com/kf/201307/227488.html #include<stdio.h> #include& ...

  6. 牛客网 暑期ACM多校训练营(第二场)J.farm-STL(vector)+二维树状数组区间更新、单点查询 or 大暴力?

    开心.jpg J.farm 先解释一下题意,题意就是一个n*m的矩形区域,每个点代表一个植物,然后不同的植物对应不同的适合的肥料k,如果植物被撒上不适合的肥料就会死掉.然后题目将每个点适合的肥料种类( ...

  7. 【poj2155】Matrix(二维树状数组区间更新+单点查询)

    Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the ...

  8. 1082 线段树练习 3 && 树状数组区间修改区间查询

    1082 线段树练习 3 题意: 给定序列初值, 要求支持区间修改, 区间查询 Solution 用树状数组, 代码量小, 空间占用小 巧用增量数组, 修改时在 \(l\) 处 $ + val$ , ...

  9. Educational Codeforces Round 10 D. Nested Segments 【树状数组区间更新 + 离散化 + stl】

    任意门:http://codeforces.com/contest/652/problem/D D. Nested Segments time limit per test 2 seconds mem ...

随机推荐

  1. 鸟哥Linux私房菜(基础篇)——第十一章:认识与学习Bash

    1.变量的取用与设定 ●变量的取用:echo ●变量的设定规则 变量与变量内容以一个等号『=』来连结. 等号两边不能直接接空格符. 变量名称只能是英文字母和数字,但是开头字符不能是数字. 变量内容若有 ...

  2. HDU 6341 Let Sudoku Rotate

    #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #defi ...

  3. 虚拟机 VMware Workstation Pro 15.5.0 及永久激活密钥

    虚拟机 VMware Workstation Pro 15.5.0 及永久激活密钥 虚拟机下载地址:https://download3.vmware.com/software/wkst/file/VM ...

  4. SQL Server遍历表中记录的2种方法

    SQL Server遍历表一般都要用到游标,SQL Server中可以很容易的用游标实现循环,实现SQL Server遍历表中记录.本文将介绍利用使用表变量和游标实现数据库中表的遍历. 表变量来实现表 ...

  5. C++如何求程序运行时间

    C++中常用clock()函数求运行时间,返回值类型为clock_t,返回值是程序运行到本次调用clock()函数经过的clock数,头文件为<time.h>. 用法: 1.求开始时间s= ...

  6. POJ Building a Space Station 最小生成树

    Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 15664   Accepted: 6865 Description You ...

  7. Hello World的五十种不同实现方法!!!!!

    我们作为一名程序员,职业生涯中至少完成了一个“Hello, World!“程序.当我们学习一门新的语言时,“Hello, World!“通常是我们所写的第一个程序.程序员一般也都会使用多门语言,甚至有 ...

  8. vue 搭建框架到安装插件依赖,Element、axios、qs等

    一.使用vue 单页面开发,首先要安装好本地环境 步骤如下: 1 下载nodejs 安装 (此时npm 和 node环境都已经装好)2 安装淘宝镜像 npm install -g cnpm --reg ...

  9. RDP凭据离线脱取

    内网渗透-获取本地RDP密码 获取RDP 连接记录: reg query "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Clie ...

  10. ES[7.6.x]学习笔记(七)IK中文分词器

    在上一节中,我们给大家介绍了ES的分析器,我相信大家对ES的全文搜索已经有了深刻的印象.分析器包含3个部分:字符过滤器.分词器.分词过滤器.在上一节的例子,大家发现了,都是英文的例子,是吧?因为ES是 ...