题目链接
题意:
给定一个长度为 \(n(1\leq n \leq 2\times10^5)\) 的数组 \(a(1 \leq a[i]\leq10^9)\)和一个数 \(m (1\leq m \leq 60)\).
现给出 \(q(1 \leq q \leq10^5)\)次操作:
操作\(1\):输入\(1\), \(l\), \(r\), \(val\)\((1 \leq l \leq r \leq n , val \leq10^9)\) 表示将区间\([l,r]\)每个数的权值加上\(val\).
操作\(2\):输入\(2\), \(l\), \(r\) \((1 \leq l \leq r \leq n )\),查询区间\([l,r]\)每个数对 \(m\) 取余后能得到多少种不同的素数.
思路:
线段树区间更新+区间查询。
树的每个结点内开一个\(m\)大小的数组,保存结点所覆盖区间内对应数是否存在,可以用\(bitset\)优化空间。
\(bitset\)自带位运算(|、&、>>、<<),则结点区间内所有数加上一个数\(d(d<m)\),更新后为\(p = (p << d) | (p >> (m - d))\),(\(p\)为节点内\(bitset\)数组);
\(bitset\)常用操作:
foo.size() 返回大小(位数)
foo.count() 返回1的个数
foo.any() 返回是否有1
foo.none() 返回是否没有1
foo.set() 全都变成1
foo.set(p) 将第p + 1位变成1
foo.set(p, x) 将第p + 1位变成x
foo.reset() 全都变成0
foo.reset(p) 将第p + 1位变成0
foo.flip() 全都取反
foo.flip(p) 将第p + 1位取反
foo.to_ulong() 返回它转换为unsigned long的结果,如果超出范围则报错
foo.to_ullong() 返回它转换为unsigned long long的结果,如果超出范围则报错
foo.to_string() 返回它转换为string的结果
code:
#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;
const int maxn = 2e5 + 10;
#define lson rt << 1
#define rson rt << 1 | 1
struct node{
bitset<60> p;
int y;
}t[maxn << 2];
int n, m, s[maxn];
bitset<60> ans;
bool vis[60];
void init(){
vis[0] = vis[1] = 0, vis[2] = vis[3] = 1;
for(int i = 4; i < 60; i ++){
int ok = 1;
for(int j = 2; j * j <= i; j ++){
if(i % j == 0){
vis[i] = 0, ok = 0;
break;
}
}
if(ok)vis[i] = 1;
}
}
void zy(int rt, int d){
t[rt].p = (t[rt].p << d) | (t[rt].p >> (m - d));
}
void pushup(int rt){
t[rt].p = t[lson].p | t[rson].p;
}
void pushdown(int rt){
if(t[rt].y){
int &d = t[rt].y;
t[lson].y = (t[lson].y + d) % m;
t[rson].y = (t[rson].y + d) % m;
zy(lson, d), zy(rson, d);
d = 0;
}
}
void build(int rt, int l, int r){
t[rt].p.reset();
if(l == r){
int a = s[l] % m;
t[rt].p[a] = 1;
return ;
}
int mid = l + r >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(rt);
}
void update(int rt, int l, int r, int L, int R, int d){
if(L <= l && r <= R){
t[rt].y = (t[rt].y + d) % m;
zy(rt, d);
return ;
}
pushdown(rt);
int mid = l + r >> 1;
if(L <= mid)update(lson, l, mid, L, R, d);
if(mid < R)update(rson, mid + 1, r, L, R, d);
pushup(rt);
}
void query(int rt, int l, int r, int L, int R){
if(L <= l && r <= R){
ans |= t[rt].p;
return ;
}
pushdown(rt);
int mid = l + r >> 1;
if(L <= mid)query(lson, l, mid, L, R);
if(mid < R)query(rson, mid + 1, r, L, R);
}
int main(){
init();
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++)scanf("%d", &s[i]);
build(1, 1, n);
int q;
scanf("%d", &q);
while(q --){
int a, l, r, d;
scanf("%d%d%d", &a, &l, &r);
if(a == 1){
scanf("%d", &d);
update(1, 1, n, l, r, d % m);
}
else{
ans.reset();
query(1, 1, n, l, r);
int sum = 0;
for(int i = 0; i < m; i ++){
if(ans[i] && vis[i])sum ++;
}
printf("%d\n", sum);
}
}
return 0;
}