CodeForces 474F Ant colony

线段树维护区间GCD(我永远爱GCD)
和区间内值为GCD的数的个数
因为区间越大,GCD只会越来越小,所以新的GCD如果不等于原来的GCD,那么这个子区间内就不会有数等于新GCD。
根据这个性质随便搞一下就行了。

#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1000010;
int a[N],b[N];
struct Node{int gcd,cnt;Node(){gcd=cnt=0;}};
struct Segtree{
  int gcd,l,r,cnt;
  Segtree(){gcd=l=r=cnt=0;}
}t[N<<2];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void pushup(int cur) {
  int d=gcd(t[cur<<1].gcd,t[cur<<1|1].gcd);
  t[cur].gcd=d;t[cur].cnt=0;
  if(d==t[cur<<1].gcd) t[cur].cnt+=t[cur<<1].cnt;
  if(d==t[cur<<1|1].gcd) t[cur].cnt+=t[cur<<1|1].cnt;
}
void build(int l,int r,int cur) {
  t[cur].l=l;t[cur].r=r;
  if(l==r) {t[cur].gcd=a[l];t[cur].cnt=1;return;}
  int mid=l+r>>1;
  build(l,mid,cur<<1);
  build(mid+1,r,cur<<1|1);
  pushup(cur);
}
Node query(int l,int r,int cur) {
    if(t[cur].l>=l&&t[cur].r<=r) {
      Node x;x.gcd=t[cur].gcd;x.cnt=t[cur].cnt;
      return x;
    }
    int mid=t[cur].l+t[cur].r>>1;
    Node ans,tmp;
    ans.gcd=-1;
    if(l<=mid&&r>=t[cur].l) ans=query(l,r,cur<<1);
    if(t[cur].r>=l&&r>mid){
      tmp=query(l,r,cur<<1|1);
      if(ans.gcd==-1) ans=tmp;
      else {
        int d=gcd(ans.gcd,tmp.gcd);
        if(d!=ans.gcd) ans.cnt=0;
        if(d==tmp.gcd) ans.cnt+=tmp.cnt;
        ans.gcd=d;
      }
    }
    return ans;
}

int n,q,l,r;
int main() {
  scanf("%d",&n);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  build(1,n,1);
  scanf("%d",&q);
  while(q--) {
    scanf("%d%d",&l,&r);
    Node ans=query(l,r,1);
    printf("%d\n",r-l+1-ans.cnt);
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9297400.html