CSUSTOJ 簽到題(線段樹 + bitset優化)
阿新 • • 發佈:2021-10-20
題目連結
題意:
給定一個長度為 \(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 )\)
思路:
線段樹區間更新+區間查詢。
樹的每個結點內開一個\(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; }