[区间GCD预处理 树状数组 离线] HDU 5869 Different GCD Subarray Query

来源:互联网 发布:js数组删除元素splice 编辑:程序博客网 时间:2024/05/21 05:39

首先确定一个右端点 向左做后缀gcd的值是不超过log的 因为gcd必然递减 每次至少除以2
那么可以对每个右端点预处理出来
然后要求区间不同的gcd个数 这里要用到1878: [SDOI2009]HH的项链的技巧
用树状数组离线处理
按右端点的顺序处理询问
令pos[x]等于x这个值出现的最靠右的位置 显然这里是对计算贡献最有利的 然后用树状数组维护下 对于某个位置 有多少个pos的取值是在这里的

#include<cstdio>#include<cstdlib>#include<algorithm>#include<cstring>#define cl(x) memset(x,0,sizeof(x))using namespace std;typedef long long ll;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }  return *p1++;}inline int read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; else if (c==EOF) return 0;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; return 1;}const int N=100005;int n,m,a[N];struct abcd{  int l,r,d;  abcd(int l=0,int r=0,int d=0):l(l),r(r),d(d) {}}G[N][35];int cnt[N];inline void Init(){  for (int i=1;i<=n;i++){    for (int j=1;j<=cnt[i-1];j++)      G[i][j]=G[i-1][j],G[i][j].d=__gcd(G[i][j].d,a[i]);    cnt[i]=cnt[i-1]+1;    G[i][cnt[i]]=abcd(i,i,a[i]);    int pnt=0;    for (int j=1;j<=cnt[i];j++){      if (G[i][j].d!=G[i][pnt].d)    G[i][++pnt]=G[i][j];      else    G[i][pnt].r=G[i][j].r;    }    cnt[i]=pnt;  }}namespace BIT{  int maxn; ll c[N];  inline void init(int n){ maxn=n; for (int i=1;i<=n;i++) c[i]=0; }  inline void add(int x,int r){ for (int i=x;i<=maxn;i+=i&-i) c[i]+=r; }  inline ll sum(int x) { int ret=0; for (int i=x;i;i-=i&-i) ret+=c[i]; return ret; }  inline ll sum(int l,int r) { return sum(r)-sum(l-1); }}struct event{  int l,r,idx;  bool operator < (const event &B) const{ return r<B.r; }}eve[N];int tot;ll ans[N];int pos[1000005];int main(){  int T,l,r,Case=0;  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  while (read(n)){    read(tot);     for (int i=1;i<=n;i++) read(a[i]);    Init(); BIT::init(n);    for (int i=1;i<=tot;i++) read(eve[i].l),read(eve[i].r),eve[i].idx=i;    sort(eve+1,eve+tot+1);    int pnt=1;    for (int i=1;i<=n;i++){      for (int j=1;j<=cnt[i];j++){    int d=G[i][j].d,r=G[i][j].r;    if (pos[d]) BIT::add(pos[d],-1);    pos[d]=max(r,pos[d]); BIT::add(pos[d],1);      }      while (pnt<=tot && eve[pnt].r==i)    ans[eve[pnt].idx]=BIT::sum(eve[pnt].l,eve[pnt].r),pnt++;    }    for (int i=1;i<=tot;i++)      printf("%I64d\n",ans[i]);    cl(pos);  }  return 0;}
0 0