HDU - 6964 I love counting(树状数组套字典树)

题目链接

题目大意

  询问区间内满足\(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;
    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 t = a>>i&1;
        if (b>>i&1) {
            sum += cnt[tr[p][t]];
            p = tr[p][t^1];
        }
        else p = tr[p][t];
        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;
}
posted @ 2021-07-30 11:14  shuitiangong  阅读(163)  评论(0编辑  收藏  举报