题目大意:求区间$[L,R]$中所有子区间产生的最大公因数的个数。

-------------------------

对于$gcd$,我们知道$gcd(a,b,c)=gcd(gcd(a,b),c)$。所以我们可以利用$gcd$的传递性来求区间的$gcd$。如果$gcd$相同,那么保留下来位置相对靠右的那一个,这与我们查询的方式有关。我们在查询时是$O(n)$正向遍历的,询问的区间按照右端点进行关键字排序,每次维护一个新的$gcd$最靠右的位置并让这个位置+1,让之前的位置-1即可。

因为每次$gcd$结果至少除以2,所以复杂度降成了$\log$级别的。总复杂度$O(n\log n)$。

小细节:线段树建树的时候一定要从$0$开始建树,因为$pre[gcd]$是有可能等于$0$的。

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=;
int a[maxn],n,T;
struct node
{
int p,g;
};
struct qq
{
int l,r,id;
}q[maxn];
struct t
{
int l,r,sum;
}tree[maxn<<];
vector<node> v[maxn];
int pre[*maxn];
int res[maxn];
inline int read()
{
int x=,f=;char ch=getchar();
while(!isdigit(ch)){if (ch=='-') f=-;ch=getchar();}
while(isdigit(ch)){x=x*+ch-'';ch=getchar();}
return x*f;
}
int gcd(int a,int b)
{
if (!b) return a;
return gcd(b,a%b);
}
int cmp(qq a,qq b)
{
return a.r<b.r;
}
inline void build(int index,int l,int r)
{
tree[index].l=l;
tree[index].r=r;
if (l==r)
{
tree[index].sum=;
return;
}
int mid=(l+r)>>;
build(index*,l,mid);
build(index*+,mid+,r);
}
void change(int index,int pos,int x)
{
if (tree[index].l==tree[index].r)
{
tree[index].sum+=x;
return;
}
int mid=(tree[index].l+tree[index].r)>>;
if (mid>=pos) change(index*,pos,x);
else change(index*+,pos,x);
tree[index].sum=tree[index*+].sum+tree[index*].sum;
}
int query(int index,int l,int r)
{
if (l<=tree[index].l&&tree[index].r<=r)
{
return tree[index].sum;
}
int ans=,mid=(tree[index].l+tree[index].r)>>;
if (mid>=l) ans+=query(index*,l,r);
if (mid<r) ans+=query(index*+,l,r);
return ans;
}
signed main()
{
n=read(),T=read();
for (int i=;i<=n;i++) a[i]=read();
for (int i=;i<=T;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
build(,,n);
for (int i=;i<=n;i++)
{
int x=a[i],y=i,k=v[i-].size();
for (int j=;j<k;j++)
{
int u=v[i-][j].g;
int gg=gcd(u,x);
if (x!=gg)
{
v[i].push_back((node){y,x});
y=v[i-][j].p;
x=gg;
}
}
v[i].push_back((node){y,x});
}
sort(q+,q+T+,cmp);
int now=;
for (int i=;i<=n;i++)
{
int k=v[i].size();
for (int j=;j<k;j++)
{
int pp=v[i][j].p;
int gg=v[i][j].g;
change(,pre[gg],-);
pre[gg]=pp;
change(,pp,);
}
while (q[now].r==i)
{
int id=q[now].id;
res[id]=query(,q[now].l,q[now].r);
now++;
if (now>T) break;
}
}
//for (int i=1;i<=n<<2;i++) cout<<tree[i].sum<<endl;
for (int i=;i<=T;i++) printf("%lld\n",res[i]);
return ;
}

【HDU5869】 Different GCD Subarray Query 题解 (线段树维护区间GCD)的更多相关文章

  1. Can you answer these queries V SPOJ - GSS5 (分类讨论+线段树维护区间最大子段和)

    recursion有一个整数序列a[n].现在recursion有m次询问,每次她想知道Max { A[i]+A[i+1]+...+A[j] ; x1 <= i <= y1 , x2 &l ...

  2. CodeForces - 587E[线段树+线性基+差分] ->(线段树维护区间合并线性基)

    题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 做法一:对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线 ...

  3. POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )

    POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...

  4. 线段树维护区间前k小

    线段树维护区间前k小 $ solution: $ 觉得超级钢琴太麻烦?在这里线段树提供一条龙服务 . 咳咳,开始讲正题!这道题我们有一个和超级钢琴复杂度一样 $ ~O(~\sum x\times lo ...

  5. FJUT3568 中二病也要敲代码(线段树维护区间连续最值)题解

    题意:有一个环,有1~N编号,m次操作,将a位置的值改为b,问你这个环当前最小连续和多少(不能全取也不能不取) 思路:用线段树维护一个区间最值连续和.我们设出两个变量Lmin,Rmin,Mmin表示区 ...

  6. hdu_5726_GCD(线段树维护区间+预处理)

    题目链接:hdu_5726_GCD 题意: 给你n个数(n<=1e5)然后m个询问(m<=1e5),每个询问一个区间,问你这个区间的GCD是多少,并且输出从1到n有多少个区间的GCD和这个 ...

  7. 51nod 1376【线段树维护区间最大值】

    引自:wonter巨巨的博客 定义 dp[i] := 以数字 i(不是下标 i)为结尾的最长上升长度 然后用线段树维护 dp[i]: 每个节点维护 2 个信息,一个是当前区间的最大上升长度,一个是最大 ...

  8. 滑动窗口(poj,线段树维护区间最值)

    题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...

  9. [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)

    题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...

随机推荐

  1. meta viewport相关

    <!DOCTYPE html> H5标准声明,使用 HTML5 doctype,不区分大小写 <head lang=”en”> 标准的 lang 属性写法 <meta c ...

  2. java学习第五天2020/7/10

    一. 今天继续学习算法: 1. 查找,一般我们采用的是顺序查找的方法,这种方法是比较简单,但是效率却很低:一般就是从第一个数开始与想要查找的那个数进行比较,当遇到相同的时候则就成功查找了: 另一种比较 ...

  3. 一篇夯实一个知识点系列--python装饰器

    写在前面 本系列目的:希望可以通过一篇文章,不望鞭辟入里,但求在工程应用中得心应手. 装饰器模式是鼎鼎大名的23种设计模式之一.装饰器模式可以在不改变原有代码结构的情况下,扩展代码功能. Python ...

  4. Scala 面向对象(三):package 包 (二)

    1 包对象 基本介绍:包可以包含类.对象和特质trait,但不能包含函数/方法或变量的定义.这是Java虚拟机的局限.为了弥补这一点不足,scala提供了包对象的概念来解决这个问题. package ...

  5. 机器学习实战基础(二十九):决策树(二)DecisionTreeClassifier与红酒数据集

    DecisionTreeClassifier与红酒数据集 1 sklearn.tree.DecisionTreeClassifier class sklearn.tree.DecisionTreeCla ...

  6. 什么是A站、B站、C站、D站、E站、F站、G站、HIJKLM站N站?

    A站AcFun弹幕视频网,简称“A站”,成立于2007年6月,取意于Anime Comic Fun,是中国大陆第一家弹幕视频网站.A站以视频为载体,逐步发展出基于原生内容二次创作的完整生态,拥有高质量 ...

  7. Python Ethical Hacking - Bypass HTTPS(1)

    HTTPS: Problem: Data in HTTP is sent as plain text. A MITM can read and edit requests and responses. ...

  8. .Net Core+Nginx实现项目负载均衡

    nginx大家如果没用过那或多或少都应该听过,vue的部署.反向代理.负载均衡nginx都能帮你做到. 今天主要说一下nginx负载均衡我们的项目,如下图所示,请求到达nginx,nginx再帮我们转 ...

  9. CENTOS下搭建git代码仓库 ssh协议

    centos服务器下搭建git仓库,使用ssh协议管理仓库代码权限    git官网(http://git-scm.com/) 使用ssh协议: 一.安装git,使用yum install git 或 ...

  10. CSS3伪类 :empty

    :empty 种类:伪类选择器 版本:CSS3.0 用法:匹配每个没有子元素(包含文本)的元素. 例子: <!DOCTYPE html> <html> <head> ...