HDU - 6964 I love counting(樹狀陣列套字典樹)
阿新 • • 發佈:2021-07-30
題目大意
詢問區間內滿足\(c\ xor\ a < b\)的不同的數的個數。
解題思路
求區間不同的數可以用樹狀陣列離線來做,求滿足\(c\ xor\ a < b\)的數可以用字典樹來做,樹狀陣列的每一個節點開一個字典樹即可。算是兩種思路的結合吧。
const int maxn = 1e5+10; const int maxm = maxn*400; int n, m, a[maxn]; int tr[maxm][2], cnt[maxm], idx; int c[maxn], rt[maxn], lst[maxn], ans[maxn]; struct INFO { int l, a, b, i; }; vector<INFO> q[maxn]; void insert(int &p, int v, int x) { if (!p) p = ++idx; int now = p; //不能用p往下走,因為上面是引用 for (int i = 20; i>=0; --i) { int t = x>>i&1; if (!tr[now][t]) tr[now][t] = ++idx; now = tr[now][t]; cnt[now] += v; } } void add(int x, int v, int y) { while(x<=n) { insert(rt[x], v, y); x += x&-x; } } int query(int p, int a, int b) { int sum = 0; for (int i = 20; i>=0; --i) { int t1 = a>>i&1; int t2 = b>>i&1; /* a b 1 1 1++ 0 0 1 0++ 1 1 0 1 0 0 0 */ if (t2) { if (t1) sum += cnt[tr[p][1]], p = tr[p][0]; else sum += cnt[tr[p][0]], p = tr[p][1]; } else { if (t1) p = tr[p][1]; else p = tr[p][0]; } if (!p) break; } return sum+cnt[p]; } int ask(int x, int a, int b) { int sum = 0; while(x) { sum += query(rt[x], a, b); x -= x&-x; } return sum; } int main() { IOS; cin >> n; for (int i = 1; i<=n; ++i) cin >> a[i]; cin >> m; for (int i = 1; i<=m; ++i) { int l, r, c, d; cin >> l >> r >> c >> d; q[r].push_back({l, c, d, i}); } for (int i = 1; i<=n; ++i) { if (lst[a[i]]) add(lst[a[i]], -1, a[i]); add(i, 1, a[i]); //for (int j = 1; j<=n; ++j) cout << rt[j] << endl; lst[a[i]] = i; for (auto v : q[i]) ans[v.i] = ask(i, v.a, v.b)-ask(v.l-1, v.a, v.b); } for (int i = 1; i<=m; ++i) cout << ans[i] << endl; return 0; }