【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 ...
随机推荐
- centos7 安装部署 Jenkins
Jenkins 安装部署 1. 安装资源下载 Jenkin镜像地址: http://mirrors.jenkins-ci.org/status.html 选择清华大学镜像地址下载rpm https:/ ...
- Pop!_OS下安装C++编程工具
Pop!_OS下C++编程 #0x0 Visual Studio Code #0x1 C++ 0x11 code::blocks #0x0 Visual Studio Code 下载安装vscode ...
- idea 项目启动console卡在Connected to the target VM, address: '127.0.0.1:51140', transport: 'socket'不动了
- Burp Suite Spider Module - 网络爬虫模块
Web application spdiering 和scanning 可以结合使用. Burp Suite 的Spider Module - Options 主要包含:Crawler Setting ...
- 程序员为什么要使用Markdown
为什么要学习markdown? 一个让你难以拒绝的理由:markdown可以让你养成了记录的习惯. 我自从使用了markdown之后,就喜欢了写文档,记录工作日志,记录周会,记录季度计划,记录学习目标 ...
- 多国正在遭遇新型勒索病毒Petya侵袭
北京时间2017年6月27日晚,据外媒消息,多国正在遭遇 Petya 勒索病毒袭击,政府.银行.电力系统.通讯系统.企业以及机场都受到不同程度影响.请予关注,并做相应防范.相关事件描述及防范措施如下: ...
- Shell基本语法---处理海量数据的sed命令
sed命令 shell脚本三剑客之一 处理时,把当前处理的行存储在临时缓冲区中,称为模式空间,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕.接着处理下一行,这样不断重复,直到 ...
- java opencsv解析csv文件
记一次使用opencsv解析csv文件时碰到的坑 最近在开发过程中需要解析csv文件,公司用的解析工具是opencsv,在根据opencsv的官方文档去解析时发现csv文件中含有繁体字,使用其自带的C ...
- 疑难杂症1-去掉网站里的特殊编码
编辑器:Visual Studio 2019项目框架:Net Core 3.1 + AutoFac 特殊符号,这是编码UTF-8 + BOM的特殊标记,是隐藏的,但是会被浏览器翻 ...
- 用windbg查看dmp文件,定位bug位置
windbg + .dmp + .pdb + 源代码,可以看到是哪个代码崩溃的 设置符号文件所在路径 File->Symbol File Path... 在输入框中填入.pdb文件所在的文件夹路 ...