bzoj5301 [莫队]

5301: [Cqoi2018]异或序列

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 117   Solved: 88
[ Submit][ Status][ Discuss]

Description

已知一个长度为 n 的整数数列 a[1],a[2],…,a[n] ,给定查询参数 l、r ,问在 [l,r] 区间内,有多少连续子
序列满足异或和等于 k 。
也就是说,对于所有的 x,y (l≤x≤y≤r),能够满足a[x]^a[x+1]^…^a[y]=k的x,y有多少组。

Input

输入文件第一行,为3个整数n,m,k。
第二行为空格分开的n个整数,即ai,a2,….an。
接下来m行,每行两个整数lj,rj,表示一次查询。
1≤n,m≤105,O≤k,ai≤105,1≤lj≤rj≤n

Output

输出文件共m行,对应每个查询的计算结果。

Sample Input

4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4

Sample Output

4
2
1
2
1

HINT

Source

鸣谢Amphetamine整理题面&&codeforces 617E

[ Submit][ Status][ Discuss]



这题范围是1e5。

连续异或和,一般考虑保存异或前缀和。区间静态操作题,考虑写一手莫队。

异或真是个神奇的东西。若a^b=c,则a^c=b且b^c=a。

定义cnt[i]为当前区间值为i的前缀的数量(这正是a的值域≤1e5的用意),那我们更新答案时就可以O(1)计算每个增加(删除)节点的贡献。

Code留坑。

/**************************************************************
    Problem: 5301
    User: LoveOI
    Language: C++
    Result: Accepted
    Time:1568 ms
    Memory:5200 kb
****************************************************************/
 
#include <cstdio>
#include <cmath>
#include <algorithm>
#define N 100010
using namespace std;
inline char gc() {
    static char now[1<<16], *S, *T;
    if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
    return *S++;
}
inline int read() {
    int x = 0; char c = gc();
    while(c < '0' || c > '9') c = gc();
    while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
    return x;
}
inline void print(long long x) {
    if(!x) {puts("0"); return ;}
    int dgt[30], now = -1;
    while(x) {dgt[++now] = (int)x % 10; x/= 10;}
    for(int i = now; i >= 0; --i) putchar('0' + dgt[i]); puts("");
}
int n, m, k; long long a[N], blank, s[N], answer[N], cnt[N];
struct node {int l, r, id;}q[N];
inline bool cmp1(node A, node B) {
    int b1 = (A.l - 1)/blank, b2 = (B.l - 1)/blank;
    if(b1 == b2) return (b1&1)?(A.r<B.r):(A.r > B.r);
    return b1 < b2;
}
int main() {
    n = read(); m = read(); k = read();
    for(int i = 1; i <= n; ++i) a[i] = read();
    s[0] = 0; for(int i = 1; i <= n; ++i) s[i] = s[i - 1] ^ a[i];
    for(int i = 1; i <= m; ++i) {q[i].l = read(); q[i].r = read(); q[i].id = i;}
    blank = (int)sqrt(n); sort(q+1, q+m+1, cmp1);
    int l = 1, r = 0; long long ans = 0;
    for(int i = 1; i <= m; ++i) {
        while(l < q[i].l - 1) {--cnt[s[l]]; ans-= cnt[k^s[l]]; ++l;}
        while(l > q[i].l - 1) {--l; ans+= cnt[k^s[l]]; ++cnt[s[l]];}
        while(r < q[i].r) {++r; ans+= cnt[k^s[r]]; ++cnt[s[r]];}
        while(r > q[i].r) {--cnt[s[r]]; ans-= cnt[k^s[r]]; --r;}
        answer[q[i].id] = ans;
    }
    for(int i = 1; i <= m; ++i) print(answer[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/richard_for_oi/article/details/80016650