1. 程式人生 > >洛谷 P4462 [CQOI2018]異或序列(優雅的莫隊)

洛谷 P4462 [CQOI2018]異或序列(優雅的莫隊)

題目

自己看

思路

嗯,裸的莫隊。

複習莫隊,離線將詢問按左端點所在的塊和右端點排序,然後求出[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; }