CSUSTOJ 签到题(线段树 + bitset优化)

题目链接
题意:
给定一个长度为 \(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;
}
上一篇:12.15学习


下一篇:1377. T 秒后青蛙的位置,unordered_map+bitset,学习复合类型关键字如何添加hash函数