题解 SP13015
题目描述:
给定初始序列 \(A\),然后对原序列有以下操作:
- 操作 \(1\): 0 l r v将区间 \([l,r]\) 全赋值为 \(v\)。
- 操作 \(2\):1 l r查询区间 \([l,r]\) 的质数个数。
注意:多组测试和特殊的输出。
题目分析:
就是一道板子题,首先我们先用欧拉筛筛出值域 \([2,10^6]\) 内的素数并开桶打标记(实际上一个欧拉筛就行了)。
此时,线段树维护的是当前区间内质数的个数,我们可以将操作 \(1\) 变成如下操作:
- 若 \(v\) 属于质数,则将区间 \([l,r]\) 内的数全赋值成 \(1\)。
- 若 \(v\) 不属于质数,则将区间 \([l,r]\) 内的数全赋值成 \(0\)。
那么,操作 \(2\) 此时显然就变成了一个区间求和。
时间复杂度,\(O(n\lg n)\)。
代码实现:
#include <bits/stdc++.h>
#define dbg(x) cerr<<#x<<": "<<x<<endl;
using namespace std;
#define MAX_SIZE (int)2e6
#define MAX_RANGE (int)1.1e6
bool nf[MAX_RANGE];
int primes[MAX_RANGE];
inline void primeshai(int n){
    for(register int i=2;i<=n;i++){
        if(!nf[i])
            primes[++primes[0]] = i;
        for(register int j=1;j<=primes[0]&&primes[j]*i<=n;j++){
            nf[primes[j]*i] = 1;
            if(i%primes[j]==0)
                break;
        }
    }
}
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
struct SegmentTree{
    int sum;
    int lazy;
    int l,r;
    int len;
};
SegmentTree seg[MAX_SIZE<<2];
int a[MAX_SIZE];
void build(int p,int l,int r)
{
    seg[p].l = l;
    seg[p].r = r;
    seg[p].lazy = -1;
    seg[p].len = r-l+1;
    if(l==r){
        seg[p].sum = !nf[a[l]];
        return;
    }
    int mid = (l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    seg[p].sum = seg[p<<1].sum + seg[p<<1|1].sum;
}
inline void spread(int p){
    if(seg[p].lazy!=-1){
        seg[p<<1].sum = seg[p].lazy*seg[p<<1].len;
        seg[p<<1|1].sum = seg[p].lazy*seg[p<<1|1].len;
        seg[p<<1].lazy = seg[p].lazy;
        seg[p<<1|1].lazy = seg[p].lazy;
        seg[p].lazy = -1;
    }
}
inline void modify(int p,int l,int r,int val){
    if(l<=seg[p].l&&r>=seg[p].r){
        seg[p].sum = val * seg[p].len;
        seg[p].lazy = val;
        return;
    }
    if(seg[p].lazy>=0)
        spread(p);
    int mid = (seg[p].l+seg[p].r)>>1;
    if(l<=mid)
        modify(p<<1,l,r,val);
    if(r>mid)
        modify(p<<1|1,l,r,val);
    seg[p].sum = seg[p<<1].sum + seg[p<<1|1].sum;
}
inline int query(int p,int l,int r){
    if(l<=seg[p].l&&r>=seg[p].r)
        return seg[p].sum;
    if(seg[p].lazy>=0)
        spread(p);
    int val = 0;
    int mid = (seg[p].l+seg[p].r)>>1;
    if(l<=mid)
        val += query(p<<1,l,r);
    if(r>mid)
        val += query(p<<1|1,l,r);
    return val;
}
int main(){
    ios::sync_with_stdio(false);
    cout.tie(0);
#ifdef LOCAL
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
    double c1 = clock();
#endif
//============================================
    primeshai(1e6);
    int T;
    T = read();
    for(int x=1;x<=T;x++){
        cout<<"Case "<<x<<':'<<endl;
        int n = read();
        int q = read();
        for(int i=1;i<=n;i++)
            a[i] = read();
        build(1,1,n);
        while(q--){
            switch(read()){
                case 0:{
                    int l = read();
                    int r = read();
                    int y = read();
                    modify(1,l,r,!nf[y]);
                    break;
                }
                case 1:{
                    int l = read();
                    int r = read();
                    cout<<query(1,l,r)<<endl;
                    break;
                }
            }
        }
    }
//============================================
#ifdef LOCAL
    double c2 = clock();
    cerr<<"Used Time: "<<c2-c1<<"ms"<<endl;
    if(c2-c1>1000)
        cerr<<"Warning!! Time Limit Exceeded!!"<<endl;
    fclose(stdin);
    fclose(stdout);
#endif
    return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号