题解:洛谷 P1890 gcd区间
- 标签:线段树,st表,分块,dp
题意
给定数列 \(a\),有 \(m\) 次询问求区间 \([l,r]\) 的最大公约数。
思路
这道题有多种写法,如标签所示。
线段树
线段树可以维护具有结合性的操作,很明显 \(\gcd\) 满足。
这道题线段树跑的慢是因为无修改操作,自然没有其他 \(O(1)\) 查询的快。
而代码很显然,一个建树一个查询即可。
复杂度 \(O(m\log n)\)。
其他做法暂时咕掉。
代码
线段树
#include<bits/stdc++.h>
#define i64 long long
#define L(a,b,c) for(int i=a;i<=b;i+=c)
#define R(a,b,c) for(int i=a;i>=b;i-=c)
using namespace std;
const int N=1e5+5,M=998244353;
int n,m,x,y,tree[4005],a[1005];
void build(int p,int l,int r){
if(l==r){tree[p]=a[l];return;}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
tree[p]=__gcd(tree[p<<1],tree[p<<1|1]);
}
int query(int p,int l,int r,int i,int j){
if(i<=l&&r<=j) return tree[p];
else{
int mid=l+r>>1,k=0;
if(i<=mid) k=query(p<<1,l,mid,i,j);
if(j>mid) k=__gcd(k,query(p<<1|1,mid+1,r,i,j));
return k;
}
}
void solve();
signed main(){
ios::sync_with_stdio(0);
solve();
return 0;
}
void solve(){
cin>>n>>m;
L(1,n,1) cin>>a[i];
build(1,1,n);
L(1,m,1){
cin>>x>>y;
cout<<query(1,1,n,x,y)<<endl;
}
}
标签:洛谷,gcd,int,题解,线段,P1890,build
From: https://www.cnblogs.com/Jessie-Pu/p/18290664