HDU 5869 Different GCD Subarray Query

时间:2023-03-08 16:10:33

离线操作,树状数组,$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-;
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=;
while(!isdigit(c)) c=getchar();
while(isdigit(c)) {x=x*+c-''; c=getchar();}
} const int maxn=+;
int T,n,Q,a[maxn],dp[maxn][],c[maxn],pre[maxn*],ans[maxn];
struct X{int L,R,id;}s[maxn]; int gcd(int a,int b) { if(b==) return a; return gcd(b,a%b); } void RMQ_init()
{
for(int i=;i<n;i++) dp[i][]=a[i];
for(int j=;(<<j)<=n;j++)
for(int i=;i+(<<j)-<n;i++)
dp[i][j]=gcd(dp[i][j-],dp[i+(<<(j-))][j-]);
} int RMQ(int L,int R)
{
int k=;
while((<<(k+))<=R-L+) k++;
return gcd(dp[L][k],dp[R-(<<k)+][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=;
for(int i=x;i>;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=;i<n;i++) scanf("%d",&a[i]);
RMQ_init(); for(int i=;i<Q;i++) scanf("%d%d",&s[i].L,&s[i].R),s[i].id=i;
sort(s,s+Q,cmp); memset(pre,,sizeof pre); memset(c,,sizeof c); int p=;
for(int i=;i<n;i++)
{
int L=,R=i,g=a[i]; while()
{
int left=L,right=R,pos1,pos2; while(left<=right)
{
int mid=(left+right)/;
if(RMQ(mid,i)==g) pos1=mid,right=mid-;
else left=mid+;
} left=L,right=R,pos2;
while(left<=right)
{
int mid=(left+right)/;
if(RMQ(mid,i)==g) pos2=mid,left=mid+;
else left=mid+;
} pos1++,pos2++;
if(pre[g]>pos2) continue;
if(pre[g]!=) update(pre[g],-);
update(pos2,); pre[g]=pos2;
pos1--,pos2--; R=pos1-; if(R<) break; g=RMQ(R,i);
} while(p<Q&&s[p].R==i+)
ans[s[p].id]=sum(s[p].R)-sum(s[p].L-), p++;
} for(int i=;i<Q;i++) printf("%d\n",ans[i]);
}
return ;
}