【codeforces 617E XOR and Favorite Number】【莫隊分塊】【多次查詢求區間[l,r]中區間異或等於k的子區間個數】
阿新 • • 發佈:2018-12-24
【連結】
【題意】
給定一個數組,多次查詢,問區間l,r中有多少個子區間滿足區間異或為k
【思路】
查詢很大,意味著每次回答的時間複雜度不能太大。對於本題,我們可以維護一個字首異或,sum[i],區間[a,b]異或為k等價於sum[a-1]^sum[b]=k,假如我們知道了[l,r],中有多少個子區間滿足,那麼可以通過異或方程的性質求出[l-1,r],[l+1,r],[l,r-1],[l,r+1]。那麼我們可以離線詢問,莫隊演算法求解。注意,c[i]表示異或為i的區間個數,c[0]=1初始化;
【程式碼】
#include<bits/stdc++.h> #define ll long long using namespace std; const ll maxn = 1e5 + 6; ll a[maxn]; ll ans[maxn]; ll sum[maxn]; ll c[maxn]; ll n, m, k; ll unit; ll tmp; struct node { ll l, r, id; }t[maxn]; ll cmp(node a, node b) { if (a.l / unit != b.l / unit)return a.l / unit < b.l / unit; return a.r < b.r; } void add(ll id) { tmp += c[a[id] ^ k]; c[a[id]]++; } void dele(ll id) { c[a[id]]--; tmp -= c[a[id] ^ k]; } void work() { c[0] = 1; ll L = 1; ll R = 0; tmp = 0; for (ll i = 1; i <= m; i++) { while (L > t[i].l) { L--; add(L - 1); } while (L < t[i].l) { dele(L - 1); L++; } while (R > t[i].r) { dele(R); R--; } while (R < t[i].r) { R++; add(R); } ans[t[i].id] = tmp; } } int main() { scanf("%lld%lld%lld", &n, &m, &k); for (ll i = 1; i <= n; i++)scanf("%lld", &a[i]),a[i]^=a[i-1]; for (ll i = 1; i <= m; i++) { scanf("%lld%lld", &t[i].l, &t[i].r); t[i].id = i; } unit = (ll)sqrt(n); sort(t + 1, t + 1 + m, cmp); work(); for (ll i = 1; i <= m; i++) { printf("%lld\n", ans[i]); } }