题目:
题解:
本来用的是map+线段树合并,然而所有质数到后面合并的话会有很多,T了
其实是个很明显的主席树了,每个点建一个树维护质因子个数,动态开点的特征可以保证空间,因为一个数最多有20个不同的质因子,查询的时候枚举质因子,算是一个常数了
代码:
#include <cstdio>
#include <map>
using namespace std;
const int N=100000;
const int sb=25;
struct hh{int l,r,w;}tree[N*120];
int num,pri[N+5],tot,zs[N+5],wz[sb],have[sb],root[N+5],size;bool ss[N+5];
void pre()
{
for (int i=2;i<=N;i++)
{
if (!ss[i]) pri[++tot]=i,zs[i]=tot;
for (int j=1;j<=tot && pri[j]*i<=N;j++)
{
ss[pri[j]*i]=1;
if (i%pri[j]==0) break;
}
}
}
int insert(int now,int l,int r,int x,int v)
{
if (!now)
{
now=++size; tree[now].l=tree[now].r=tree[now].w=0;
}
tree[now].w+=v;
if (l==r) return now;
int mid=(l+r)>>1;
if (x<=mid) tree[now].l=insert(tree[now].l,l,mid,x,v);
else tree[now].r=insert(tree[now].r,mid+1,r,x,v);
return now;
}
int merge(int i,int j,int l,int r)
{
if (i==0 || j==0) return i+j;
tree[i].w+=tree[j].w;
if (l==r) return i;
int mid=(l+r)>>1;
tree[i].l=merge(tree[i].l,tree[j].l,l,mid);
tree[i].r=merge(tree[i].r,tree[j].r,mid+1,r);
return i;
}
int qurry(int i,int j,int l,int r,int x)
{
if (l==r) return tree[j].w-tree[i].w;
int mid=(l+r)>>1;
if (x<=mid) return qurry(tree[i].l,tree[j].l,l,mid,x);
else return qurry(tree[i].r,tree[j].r,mid+1,r,x);
}
int main()
{
pre();
int T,n,m;scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);size=0;
for (int i=1;i<=n;i++)
{
root[i]=0;
int x;scanf("%d",&x);
int j=1;
while (!zs[x] && x!=1)
{
if (x%pri[j]==0)
{
int now=0;
while (x%pri[j]==0) now++,x/=pri[j];
root[i]=insert(root[i],1,n,j,now);
}
j++;
}
if (x!=1) root[i]=insert(root[i],1,n,zs[x],1);
root[i]=merge(root[i],root[i-1],1,n);
}
while (m--)
{
int l,r,d;
scanf("%d%d%d",&l,&r,&d);
int j=1;num=0;
while (!zs[d] && d!=1)
{
if (d%pri[j]==0)
{
wz[++num]=j;have[num]=0;
while (d%pri[j]==0) have[num]++,d/=pri[j];
}
j++;
}
if (d!=1) wz[++num]=zs[d],have[num]=1;
bool fff=1;
for (int i=1;i<=num;i++)
if (qurry(root[l-1],root[r],1,n,wz[i])<have[i]) {fff=0;break;}
if (!fff) printf("No\n");
else printf("Yes\n");
}
}
}