【HDU5869】 Different GCD Subarray Query 题解 (线段树维护区间GCD)
题目大意:求区间$[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)的更多相关文章
- 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 ...
- CodeForces - 587E[线段树+线性基+差分] ->(线段树维护区间合并线性基)
题意:给你一个数组,有两种操作,一种区间xor一个值,一个是查询区间xor的结果的种类数 做法一:对于一个给定的区间,我们可以通过求解线性基的方式求出结果的种类数,而现在只不过将其放在线树上维护区间线 ...
- POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 )
POJ.2763 Housewife Wind ( 边权树链剖分 线段树维护区间和 ) 题意分析 给出n个点,m个询问,和当前位置pos. 先给出n-1条边,u->v以及边权w. 然后有m个询问 ...
- 线段树维护区间前k小
线段树维护区间前k小 $ solution: $ 觉得超级钢琴太麻烦?在这里线段树提供一条龙服务 . 咳咳,开始讲正题!这道题我们有一个和超级钢琴复杂度一样 $ ~O(~\sum x\times lo ...
- FJUT3568 中二病也要敲代码(线段树维护区间连续最值)题解
题意:有一个环,有1~N编号,m次操作,将a位置的值改为b,问你这个环当前最小连续和多少(不能全取也不能不取) 思路:用线段树维护一个区间最值连续和.我们设出两个变量Lmin,Rmin,Mmin表示区 ...
- hdu_5726_GCD(线段树维护区间+预处理)
题目链接:hdu_5726_GCD 题意: 给你n个数(n<=1e5)然后m个询问(m<=1e5),每个询问一个区间,问你这个区间的GCD是多少,并且输出从1到n有多少个区间的GCD和这个 ...
- 51nod 1376【线段树维护区间最大值】
引自:wonter巨巨的博客 定义 dp[i] := 以数字 i(不是下标 i)为结尾的最长上升长度 然后用线段树维护 dp[i]: 每个节点维护 2 个信息,一个是当前区间的最大上升长度,一个是最大 ...
- 滑动窗口(poj,线段树维护区间最值)
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)
题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...
随机推荐
- POJO类中布尔类型为啥不让用isXxx命名
源码面前,了无秘密 <阿里开发规范泰山版>(2020.04.22)-->编程规约-->(一) 命名风格-->第8条规定: [强制]POJO 类中的任何布尔类型的变量,都不 ...
- Linux多任务编程之七:Linux守护进程及其基础实验(转)
来源:CSDN 作者:王文松 转自Linux公社 ------------------------------------------------------------------------- ...
- day02 java学习
Java三大版本 Write once,Run anywhere. (基于JVM虚拟机) JavaSE 标准版 JavaME 嵌入式开发 JavaEE 企业级开发 Java三大名词 JDK Java开 ...
- Python-字符串内容检测
str.isnumeric():检测字符串是否只由数字组成 str.isalpha():检测字符串是否只由字母组成 str.islower():检测字符串中所有的字母是否都为小写 str.isuppe ...
- Mysql基础(八):MySQL 表的一对一、一对多、多对多问题
将实体与实体的关系,反应到最终数据库表的设计上,将关系分为三种:一对一,一对多(多对一)和多对多,所有的关系都是表与表之间的关系; 一对一 一对一:一张表的一条记录只能与另外一条记录进行对应,反之亦然 ...
- Flask 基础组件(七):蓝图
1 蓝图资源 蓝图有自己的目录,它的所有资源都在其目录下.蓝图的资源目录是由创建Blueprint对象时传入的模块名”__name__”所在的位置决定的.同时,我们可以指定蓝图自己的模板目录和静态目录 ...
- Ethical Hacking - NETWORK PENETRATION TESTING(19)
MITM-DNS Spoofing DNS Spoofing allows us to redirect any request to a certain domain to another doma ...
- Spring-Boot 多数据源配置+动态数据源切换+多数据源事物配置实现主从数据库存储分离
一.基础介绍 多数据源字面意思,比如说二个数据库,甚至不同类型的数据库.在用SpringBoot开发项目时,随着业务量的扩大,我们通常会进行数据库拆分或是引入其他数据库,从而我们需要配置多个数据源. ...
- [日常摘要] -- 阻塞IO与非阻塞IO篇
NIO操作过程 非阻塞读/写操作 读-- 从通道读取数据到buffer,同时可以继续做别的事情,但数据都到buffer之后,线程再继续处理数据 写-- 一个线程请求写入一些数据到某通道,但不需要等待它 ...
- vue组件库用markdown生成文档
前言: 开发vue组件库需要提供组件的使用文档,最好是有渲染到浏览器的demo实例,既能操作又能查看源代码.markdown作为常用的文档编写载体,如果能在里面直接写vue组件,同时编写使用说明就再好 ...