HDU - 6287 口算训练 (主席树)(2018CCPC女生赛)

口算训练

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 359    Accepted Submission(s): 70


Problem Description
小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为 n的正整数序列 a1,a2,...,an,要求小T抛出 m个问题以训练他的口算能力。

每个问题给出三个正整数 l,r,d,小Q需要通过口算快速判断 al×al+1×...×ar1×ar是不是 d的倍数。

小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
 

Input
第一行包含一个正整数 T(1T10),表示测试数据的组数。

每组数据第一行包含两个正整数 n,m(1n,m100000),分别表示序列长度以及问题个数。

第二行包含 n个正整数 a1,a2,...,an(1ai100000),表示序列中的每个数。

接下来 m行,每行三个正整数 l,r,d(1lrn,1d100000),表示每个问题。
 

Output
对于每个问题输出一行,若是倍数,输出Yes,否则输出No。
 

Sample Input
 
  
1 5 4 6 4 7 2 5 1 2 24 1 3 18 2 5 17 3 5 35
 

Sample Output
 
  
Yes No No Yes
 

Source
 

Recommend
liuyiding
 


解题思路:没多想,直接上主席树查询了。对每一个树做质因数分解,然后插入到主席树中,主席树维护质因数个数,然后直接查询数量即可。


踩了一个大坑,主席树每一次Update都要更新根节点……



#include <iostream>
#include <algorithm>
#include <cstdio>
#include <string.h>
using namespace std;
typedef long long int ll;
const int MAXN=100015;
typedef pair<int,int> pii;
vector<pii> V[MAXN];
void init(){
    int cnt;
    for(int i=2; i<MAXN; i++){
        int x = i;
        for(int j=2; j*j<=x; j++){
            cnt = 0;
            while(x % j == 0){
                cnt++;
                x /= j;
            }
            if(cnt){
                V[i].push_back(make_pair(j, cnt));
            }
        }
        if(x > 1){
            V[i].push_back(make_pair(x, 1));
        }
    }
}

int N,Q;
int sum[MAXN*400];
int ls[MAXN*400];
int rs[MAXN*400];
int T[MAXN];
int tot=0;
void update(int P,int C,int l,int r,int &rt,int lrt){
    rt=++tot;
    ls[rt]=ls[lrt];
    rs[rt]=rs[lrt];
    sum[rt]=sum[lrt];
    if(l==r){
        sum[rt]+=C;
        return;
    }
    int m=(l+r)/2;
    if(P<=m)
        update(P,C,l,m,ls[rt],ls[lrt]);
    else
        update(P,C,m+1,r,rs[rt],rs[lrt]);
}

int query(int L,int R,int l,int r,int rt,int lrt){
    
    if(L<=l&&r<=R){
        return sum[lrt]-sum[rt];
    }
    int m=(l+r)/2;
    
    int ans=0;
    if(L<=m)
        ans+=query(L,R,l,m,ls[rt],ls[lrt]);
    if(R>m)
        ans+=query(L,R,m+1,r,rs[rt],rs[lrt]);
    return ans;
}

int main()
{
    init();
    int tt;
    scanf("%d",&tt);
    while(tt--){
        tot=0;
        memset(sum,0,sizeof(sum));
        memset(ls,0,sizeof(ls));
        memset(rs,0,sizeof(rs));
        
        int N,M;
        scanf("%d%d",&N,&M);
        int a;
        for(int i=1;i<=N;i++){
            scanf("%d",&a);
            if(a==1)
                T[i]=T[i-1];
            else{
                int pre=T[i-1];
                for(int j=0;j<V[a].size();j++){
                    update(V[a][j].first,V[a][j].second,1,MAXN-1,T[i],pre);
                    pre=T[i];//每次都要更新根节点
                }
            }
        }
        
        int l,r,d;
        while(M--){
            scanf("%d%d%d",&l,&r,&d);
            
            if(d==1){
                printf("Yes\n");
            }
            else{
                bool flag=1;
                
                for(int j=0;j<V[d].size();j++){
                    if(query(V[d][j].first,V[d][j].first,1,MAXN-1,T[l-1],T[r])<V[d][j].second)
                        flag=0;
                }
                
                if(flag)
                    printf("Yes\n");
                else
                    printf("No\n");
            }
            
        }
        
    }
    
    return 0;
}










猜你喜欢

转载自blog.csdn.net/lzc504603913/article/details/80509831