Evanyou Blog 彩带

区间出现偶数次的数的异或和

题目描述

初始给定n个卡片拍成一排,其中第i个卡片上的数为x[i]。
有q个询问,每次询问给定L和R表示,询问的区间【L,R】内的卡片所有出现了偶数次的数的异或和是多少。

输入

输入一行两个整数n,q。
第二行n个整数,第i个数为x[i]。
接下来q行,每行两个整数L和R,表示询问的区间。

输出

输出q行,其中第i行表示第i次询问的区间出现偶数次的数的异或和。

样例输入

3 1
3 7 8
1 3

样例输出

0

solution

①、区间内出现偶数次的数异或和 = 区间内出现奇数次的数的异或和^区间内出现过的数的异或和
②、区间内出现奇数次的数的异或和 = 区间所有数的异或和

所以,区间内出现偶数次的数异或和 = 区间所有数的异或和^区间内出现过的数的异或和

于是问题转化成求区间内出现过的数的异或和:

这里树状数组sum(i)的含义就是指以当前i为结尾的前缀区间的不同数的异或和

先对询问按右端点排序

然后遍历每个询问,对于当前位置p,如果当前位置上的数x在之前出现过,把它在之前位置上的影响删除:
$ add(last[x],x);//由异或的性质可以知道,再异或一次就可以消除影响) $

把它在当前位置的影响插入:
$ add(p,x); $
更新记录最后位置的数组 $ last[i] $

#include <iostream>
#include <cstdio>
#include <cstring> 
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>
#define re register
#define ll long long
using namespace std ;
const int maxn = 1000005 ;

inline int read () {
	int f = 1 , x = 0 ;
	char ch = getchar () ;
	while(ch > '9' || ch < '0')  {if(ch == '-')  f = -1 ; ch = getchar () ;}
	while(ch >= '0' && ch <= '9')  {x = (x << 1) + (x << 3) + ch - '0' ; ch = getchar () ;}
	return x * f ;
}

int n , q , x[maxn] ;
int xorsum[maxn] , ans[maxn] , b[maxn] ;
int last[maxn] ;

struct Tree {
    int l , r , ind ;
}tree[maxn] ;

bool cmp(Tree a , Tree b) {
    return a.r < b.r ;
}

inline int lowbit(int x) {
    return x & -x ;
}

inline void add(int pos , int val){
    while(pos <= n) {
        b[pos] ^= val ;
        pos += lowbit(pos) ;
    }
}

inline int sum(int pos) {
    int res = 0 ;
    while (pos >= 1) {
        res ^= b[pos] ;
        pos -= lowbit(pos) ;
    }
    return res ;
}

int main() {
	freopen("C.in" , "r" , stdin) ;
	freopen("C.out" , "w" , stdout) ;
    n = read () ; q = read () ;
    for(re int i = 1 ; i <= n ; ++ i) {
        x[i] = read () ;
        xorsum[i] = xorsum[i - 1] ^ x[i] ;
    }
    for(re int i = 1 ; i <= q ; ++ i) {
        tree[i].l = read () ;  tree[i].r = read () ;
        tree[i].ind = i ;
    }
    sort(tree + 1 , tree + q + 1 , cmp) ;
    for(re int i = 1 , j = 1 ; i <= q ; ++ i) {
        while(j <= tree[i].r) {
            if(last[x[j]]) 
				add(last[x[j]] , x[j]) ; 
            last[x[j]] = j ;
            add(j , x[j]) ; 
            j++ ;
        }
        ans[tree[i].ind] = sum(tree[i].r) ^ sum(tree[i].l - 1) ^ xorsum[tree[i].r] ^ xorsum[tree[i].l - 1] ;
    }
    for(re int i = 1 ; i <= q ; ++ i)
        printf("%d\n" , ans[i]) ;
    return 0 ;
}	
posted @ 2019-05-30 20:16  Stephen_F  阅读(666)  评论(0编辑  收藏  举报