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;
}