[BZOJ5358][Lydsy1805月赛]口算训练(主席树)

题目:

我是超链接

题解:

本来用的是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");
        }
    }
}

猜你喜欢

转载自blog.csdn.net/blue_cuso4/article/details/80472134
今日推荐