Loading

题解:洛谷 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;
  }
}
posted @ 2024-07-08 20:40  jess1ca1o0g3  阅读(87)  评论(0)    收藏  举报