BZOJ 5358 口算训练/HDU 6287(可持久化线段树)
题意:给你L,R区间然后给你一个K,询问L到R区间的数知否能整除K
思路:因为我们是判断是否整除,所以我们可以对每一个数进行质因数分解,然后判断L到R区间内的数质因数分解后的个数大小就可以了,然后就是打表,进行主席树维护
代码:
#include <cstdio> const int maxn=1e5+7; bool prime[maxn]; int pri[maxn],id[maxn],tot=0; int root[maxn]; struct node { int l,r,sum; }T[maxn*40]; int cnt; inline int read() { int x=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();} return x; } void getprime() { for(int i=2;i<maxn;i++){ if(!prime[i])pri[++tot]=i,id[i]=tot; for(int j=1;j<=tot&&pri[j]*i<maxn;j++){ prime[pri[j]*i]=1; if(i%pri[j]==0)break; } } } void update(int l,int r,int &x,int pos,int v) { T[++cnt]=T[x],x=cnt; if(l==r){ T[x].sum+=v; return ; } int mid=(l+r)>>1; if(pos<=mid)update(l,mid,T[x].l,pos,v); else update(mid+1,r,T[x].r,pos,v); } bool query(int l,int r,int x,int y,int pos,int v) { if(l==r){ return T[y].sum-T[x].sum>=v; } int mid=(l+r)>>1; if(pos<=mid)query(l,mid,T[x].l,T[y].l,pos,v); else query(mid+1,r,T[x].r,T[y].r,pos,v); } int main() { getprime(); int t,n,m,x,l,r,k,num,ok; scanf("%d",&t); while(t--){ cnt=0,n=read();m=read(); for(int i=1;i<=n;i++){ root[i]=root[i-1]; x=read(); for(int j=1;j<=tot&&pri[j]*pri[j]<=x;++j){ num=0; while(x%pri[j]==0)x/=pri[j],++num; if(num)update(1,tot,root[i],j,num); } if(x!=1)update(1,tot,root[i],id[x],1); } for(int i=1;i<=m;i++){ l=read(),r=read(),k=read(); ok=false; for(int j=1;j<tot&&pri[j]*pri[j]<=k;j++){ num=0; while(k%pri[j]==0)k/=pri[j],++num; if(num&&!query(1,tot,root[l-1],root[r],j,num))ok=1; if(ok)break; } if(k!=1&&!query(1,tot,root[l-1],root[r],id[k],1))ok=1; if(ok)puts("No"); else puts("Yes"); } } return 0; }