洛谷 P4462 [CQOI2018]異或序列(優雅的莫隊)
阿新 • • 發佈:2019-02-03
題目
思路
嗯,裸的莫隊。
複習莫隊,離線將詢問按左端點所在的塊和右端點排序,然後求出[l,r]可以O(1)擴充套件一步。時間複雜度O(n^1.5)。
這題就是求異或字首和,然後我們發現擴張一個格子可以計算貢獻,並在桶裡加或減。注意這裡的左端點要減1,莫隊注意先搞右再搞左,程式碼還是寫得很優雅的。
程式碼
#include <bits/stdc++.h>
#define maxn 100100
using namespace std;
int n, m, k, block, answer;
int a[maxn], ans[maxn], cnt[maxn];
struct Query{
int l, r, id;
bool operator < (const Query& OTHER) const{
if((l-1) / block == (OTHER.l-1) / block) return r < OTHER.r;
return (l-1) / block < (OTHER.l-1) / block;
}
}q[maxn];
void Insert(int x){
cnt[x] ++;
answer += cnt[x^k];
}
void Remove(int x){
answer -= cnt[x ^k];
cnt[x] --;
}
int main(){
scanf("%d%d%d", &n, &m, &k);
block = (int)sqrt(n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 2; i <= n; i++) a[i] ^= a[i-1];
for(int i = 1; i <= m; i++){
scanf("%d%d", &q[i].l, &q[i] .r);
q[i].id = i;
}
sort(q+1, q+1+m);
int l = 1, r = 0;
for(int i = 1; i <= m; i++){
while(r < q[i].r) Insert(a[++r]);
while(r > q[i].r) Remove(a[r--]);
while(l < q[i].l-1) Remove(a[l++]);
while(l > q[i].l-1) Insert(a[--l]);
ans[q[i].id] = answer;
}
for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}