离线操作,树状数组,$RMQ$。
这个题的本质和$HDU$ $3333$是一样的,$HDU$ $3333$要求计算区间内不同的数字有几个。
这题稍微变了一下,相当于原来扫描到$i$的之后是更新$a[i]$的情况,现在是更新$log$级别个数的数字(因为以$i$为结尾的区间,最多只有$log$级别种不同的$gcd$)。
求区间$gcd$可以用$RMQ$预处理一下,然后就可以$O(1)$查询了。
#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include<queue> #include<stack> #include<iostream> using namespace std; typedef long long LL; const double pi=acos(-1.0),eps=1e-6; void File() { freopen("D:\in.txt","r",stdin); freopen("D:\out.txt","w",stdout); } template <class T> inline void read(T &x) { char c=getchar(); x=0; while(!isdigit(c)) c=getchar(); while(isdigit(c)) {x=x*10+c-'0'; c=getchar();} } const int maxn=100000+10; int T,n,Q,a[maxn],dp[maxn][30],c[maxn],pre[maxn*10],ans[maxn]; struct X{int L,R,id;}s[maxn]; int gcd(int a,int b) { if(b==0) return a; return gcd(b,a%b); } void RMQ_init() { for(int i=0;i<n;i++) dp[i][0]=a[i]; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++) dp[i][j]=gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int RMQ(int L,int R) { int k=0; while((1<<(k+1))<=R-L+1) k++; return gcd(dp[L][k],dp[R-(1<<k)+1][k]); } bool cmp (X a,X b) { return a.R<b.R; } int lowbit(int x) {return x&(-x);} int sum(int x) { int res=0; for(int i=x;i>0;i=i-lowbit(i)) res=res+c[i]; return res; } void update(int x,int v) { for(int i=x;i<=n;i=i+lowbit(i)) c[i]=c[i]+v; } int main() { while(~scanf("%d%d",&n,&Q)) { for(int i=0;i<n;i++) scanf("%d",&a[i]); RMQ_init(); for(int i=0;i<Q;i++) scanf("%d%d",&s[i].L,&s[i].R),s[i].id=i; sort(s,s+Q,cmp); memset(pre,0,sizeof pre); memset(c,0,sizeof c); int p=0; for(int i=0;i<n;i++) { int L=0,R=i,g=a[i]; while(1) { int left=L,right=R,pos1,pos2; while(left<=right) { int mid=(left+right)/2; if(RMQ(mid,i)==g) pos1=mid,right=mid-1; else left=mid+1; } left=L,right=R,pos2; while(left<=right) { int mid=(left+right)/2; if(RMQ(mid,i)==g) pos2=mid,left=mid+1; else left=mid+1; } pos1++,pos2++; if(pre[g]>pos2) continue; if(pre[g]!=0) update(pre[g],-1); update(pos2,1); pre[g]=pos2; pos1--,pos2--; R=pos1-1; if(R<0) break; g=RMQ(R,i); } while(p<Q&&s[p].R==i+1) ans[s[p].id]=sum(s[p].R)-sum(s[p].L-1), p++; } for(int i=0;i<Q;i++) printf("%d ",ans[i]); } return 0; }