P5670
prob:
1.區間加
2.區間異或和後 m 位 (\(m \le 10\))
3.n 1e5
sol:
用 bitset 維護線段樹區間。
具體的,開 1024 位 bitset 表示每種數對異或貢獻為 0/1,有區間可加性。
時間複雜度 \(O(\frac{n \log n 2^m}{w})\),但是這題半秒,很卡常,需要最佳化。。(感覺甚至不如暴力/lh)
發現區間較小時 bitset 算確實不如暴力優,令長度小於閾值的區間暴力算即可。
注意:
1.暴力算的時候要把當前節點的 tag 加上。
2.不要習慣性的把迴圈裡所有東西都寫成 i !!!(modify 裡那個 p)
namespace sgt {
#define ls(p) p<<1
#define rs(p) p<<1|1
const int M = 1<<10;
const int B = 1<<5; // bf range
bitset <M> b[N<<2];
int ad[N<<2];
void pushup(int p) {
b[p] = b[ls(p)]^b[rs(p)];
}
void upd(int p, int k) {
k &= M-1;
b[p] = b[p]<<k | b[p]>>M-k;
ad[p] += k;
}
void pushdown(int p) {
if(!ad[p]) return ;
upd(ls(p), ad[p]), upd(rs(p), ad[p]);
ad[p] = 0;
}
void build(int p, int l, int r) {
if(r-l+1 <= B) {
rep(i, l, r) b[p].flip(a[i]);
return ;
}
int mid = l+r>>1;
build(ls(p), l, mid), build(rs(p), mid+1, r);
pushup(p);
}
void modify(int p, int l, int r, int x, int y, int k) {
if(r-l+1 <= B) {
int lb = max(l, x), rb = min(r, y);
rep(i, lb, rb) b[p].flip(a[i]+ad[p] & M-1);
rep(i, lb, rb) a[i] += k;
rep(i, lb, rb) b[p].flip(a[i]+ad[p] & M-1);
return ;
}
if(l >= x && r <= y) return upd(p, k);
pushdown(p);
int mid = l+r>>1;
if(x <= mid) modify(ls(p), l, mid, x, y, k);
if(y > mid) modify(rs(p), mid+1, r, x, y, k);
pushup(p);
}
bitset <M> ask(int p, int l, int r, int x, int y) {
bitset <M> s;
if(r-l+1 <= B) {
int lb = max(l, x), rb = min(r, y);
rep(i, lb, rb) s.flip(a[i]+ad[p] & M-1);
return s;
}
if(l >= x && r <= y) return b[p];
pushdown(p);
int mid = l+r>>1;
if(x <= mid) s ^= ask(ls(p), l, mid, x, y);
if(y > mid) s ^= ask(rs(p), mid+1, r, x, y);
return s;
}
}
總結:bitset 太神秘!
ABC356F
唐題