ZOJ 3886 Nico Number(线段树单点更新+找规律)

来源:互联网 发布:国外域名购买代理商 编辑:程序博客网 时间:2024/05/02 04:22

题意:

定义一个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)次,所以总的时间不会超过nlog(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, Rusing 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;}
0 0
原创粉丝点击