1. 程式人生 > 其它 >CSUSTOJ 簽到題(線段樹 + bitset優化)

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\)陣列);

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