ZOJ 3911 Prime Query (素数打表+线段树单点更新、区间更新、区间查询)

Prime Query


Time Limit: 5 Seconds      Memory Limit: 196608 KB


You are given a simple task. Given a sequence A[i] with N numbers. You have to perform Q operations on the given sequence.

Here are the operations:

  • A v l, add the value v to element with index l.(1<=V<=1000)
  • R a l r, replace all the elements of sequence with index i(l<=i<= r) with a(1<=a<=10^6) .
  • Q l r, print the number of elements with index i(l<=i<=r) and A[i] is a prime number

Note that no number in sequence ever will exceed 10^7.

Input

The first line is a signer integer T which is the number of test cases.

For each test case, The first line contains two numbers N and Q (1 <= N, Q <= 100000) - the number of elements in sequence and the number of queries.

The second line contains N numbers - the elements of the sequence.

In next Q lines, each line contains an operation to be performed on the sequence.

Output

For each test case and each query,print the answer in one line.

Sample Input

1
5 10
1 2 3 4 5
A 3 1      
Q 1 3
R 5 2 4
A 1 1
Q 1 1
Q 1 2
Q 1 4
A 3 5
Q 5 5
Q 1 5

Sample Output

2
1
2
4
0
4

第二篇博客,大神勿喷~~因为一个小细节WA了三发...

题意:给你一个n(最大1e5)的数组,有三种操作:

1.A v l    给下标为l的元素加上v (v最大1000)

2.R a l r 把区间【l,r】的值全部置换为 a(a最大1e6)

3.Q l r    查询区间【l,r】的素数个数

思路由于数组中元素最大不超过1e7,而且内存够大,所以可以先打表线型筛选出1e7内的所有素数

 由于题目中有对数组的单点更新和区间更新,所以很容易想到建两个线段树,一个用来存原数组的值,一个用来存区间素数个数

每次更新数组中的数时,判断该数是否为素数,然后更新区间素数个数

废话少说,上代码~

#include<stdio.h>
#include<string.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=1e5+5;
int  a[maxn],sum[maxn<<2],tree[maxn<<2];//sum存素数个数,tree存数组元素

bool notprime[10000005];
void init() //素数打表
{
    memset(notprime,false,sizeof(notprime));//notprime[i] 为false表示i是素数
    notprime[0]=notprime[1]=true;
    for(int i=2; i<10000005; i++)
        if(!notprime[i])
        {
            if(i>10000005/i) continue;
            for(int j=i*i; j<10000005; j+=i) notprime[j]=true;
        }
}

void push_up(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

void push_down(int rt,int l,int r)
{
    if(tree[rt])
    {
        int mid=(l+r)/2;         //此处区间个数注意一下
        tree[rt<<1]=tree[rt<<1|1]=tree[rt];
        if(!notprime[tree[rt]])  //下推延迟更新,如果是素数 左/右区间长度即为素数个数  否则为0
        {
            sum[rt<<1]=mid-l+1;
            sum[rt<<1|1]=r-mid;
        }
        else
        {
            sum[rt<<1]=0;
            sum[rt<<1|1]=0;
        }
        tree[rt]=0;
    }
}

void build(int l,int r,int rt)  //建树
{
    if(l==r)
    {
        tree[rt]=a[l];
        if(!notprime[tree[rt]]) sum[rt]=1;  //走到叶子结点是素数则赋为1,默认0
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt);
}

void update_1(int p,int v,int l,int r,int rt)   //单点更新
{
    if(l==r)
    {
        tree[rt]+=v;
        if(!notprime[tree[rt]]) sum[rt]=1;    //更新完数组立马判断更新素数个数
        else                    sum[rt]=0;
        return;
    }
    push_down(rt,l,r);        //可能之前会有区间更新没有push-down下来的
    int mid=(l+r)>>1;
    if(p<=mid) update_1(p,v,lson);
    else       update_1(p,v,rson);
    push_up(rt);            //更新完孩子的再更新父节点的
}

void update_2(int L,int R,int v,int l,int r,int rt) //区间更新
{
    if(L<=l&&R>=r)
    {
        tree[rt]=v;
        if(!notprime[v]) sum[rt]=r-l+1; //同上
        else             sum[rt]=0;
        return;
    }
    push_down(rt,l,r);
    int mid=(l+r)>>1;
    if(L<=mid) update_2(L,R,v,lson);
    if(R>mid)  update_2(L,R,v,rson);
    push_up(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r)
    {
        return sum[rt];
    }
    push_down(rt,l,r);
    int mid=(l+r)>>1,ret=0;
    if(L<=mid) ret+=query(L,R,lson);
    if(R>mid)  ret+=query(L,R,rson);
    return ret;
}

int main()
{
    init();
    int t,m,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(tree,0,sizeof(tree));
        memset(sum,0,sizeof(sum));
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; i++) scanf("%d",&a[i]);
        build(1,n,1);

        char op[5];
        int l,r,v;
        while(m--)
        {
            scanf("%s",op);
            if(op[0]=='A')
            {
                scanf("%d%d",&v,&l);
                update_1(l,v,1,n,1);
            }
            else if(op[0]=='R')
            {
                scanf("%d%d%d",&v,&l,&r);
                update_2(l,r,v,1,n,1);
            }
            else
            {
                scanf("%d%d",&l,&r);
                printf("%d\n",query(l,r,1,n,1));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/QuincyTan/article/details/81560219