题意:
定义一个NicoNico-number,如果x是NicoNico-number,那么所有小于x的且与x互质的整数是一个等差数列,初始给出n个数字的数组,三种操作:
1 l r 问在[l,r]内有多少个NicoNico-number数
2 l r v 对于[l,r]内的数全部对v取余
3 k x 将第k个数换为x
对每一次询问做出输出。
解析(转):
1、首先写一个找规律的程序,发现NicoNico-number是有三种组成的第一种是素数,第二种是2的x次幂,第三种是6
2、可以建一个一张表,直接标记某个数是不是NicoNico-number
3、使用线段树维护一段区间的NicoNico-number个数,然后可以进行对某一个数的修改,和对一个区间的查询。
关键对于第二种操作。我们要知道对于一个数x取余操作,最多会执行log(x)次,因为每次取余至少数值会减少一半,所以对于每个数来说最多会有log(x)次操作,之后会因为v大于当前值,而不用执行操作。
既然取余的次数不多,那么就可以对区域操作进行暴力,维护一段区间的最大值,如果最大值小于v,那么这一段不用更新,否则就遍历的最低层进行取余。
4、对于n个数来说,查找到一个数需要log(n),一个数最多会被修改log(x)次,所以总的时间不会超过n∗log(n)∗log(x)。
my code
#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int MAXX = (int)1e7 + 5;
const int MAXN = (int)1e5 + 5;
bool nico[MAXX*2];
int A[MAXN];
int n, q;
void prepare() {
memset(nico, true, sizeof(nico));
for(int i = 2; i < MAXX; i++) {
if(!nico[i]) continue;
nico[i] = true;
for(int j = i*2; j < MAXX; j += i) {
nico[j] = false;
}
}
nico[6] = true;
for(int i = 1; i < MAXX; i <<= 1) {
nico[i] = true;
}
}
int maxv[MAXN << 2], sumv[MAXN << 2];
void pushUp(int o) {
maxv[o] = max(maxv[ls], maxv[rs]);
sumv[o] = sumv[ls] + sumv[rs];
}
void build(int o, int L, int R) {
if(L == R) {
maxv[o] = A[L];
sumv[o] = nico[A[L]];
return ;
}
int M = (L + R)/2;
build(lson);
build(rson);
pushUp(o);
}
int query(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr)
return sumv[o];
int M = (L + R)/2, ret = 0;
if(ql <= M) ret += query(lson, ql, qr);
if(qr > M) ret += query(rson, ql, qr);
return ret;
}
void setValue(int o, int L, int R, int pos, int val) {
if(L == R) {
sumv[o] = nico[val];
maxv[o] = val;
return ;
}
int M = (L + R)/2;
if(pos <= M) setValue(lson, pos, val);
else setValue(rson, pos, val);
pushUp(o);
}
void modify(int o, int L, int R, int ql, int qr, int val) {
if(ql <= L && R <= qr && val > maxv[o])
return ;
if(L == R) {
maxv[o] %= val;
sumv[o] = nico[maxv[o]];
return ;
}
int M = (L + R)/2;
if(ql <= M) modify(lson, ql, qr, val);
if(qr > M) modify(rson, ql, qr, val);
pushUp(o);
}
int main() {
prepare();
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
}
build(1, 1, n);
scanf("%d", &q);
int oper, ql, qr, val;
while(q--) {
scanf("%d", &oper);
if(oper == 1) {
scanf("%d%d", &ql, &qr);
printf("%d\n", query(1, 1, n, ql, qr));
}else if(oper == 2) {
scanf("%d%d%d", &ql, &qr, &val);
modify(1, 1, n, ql, qr, val);
}else {
scanf("%d%d", &ql, &val);
setValue(1, 1, n, ql, val);
}
}
}
return 0;
}