「eJOI2019」异或橙子

题目链接

首先先来两个引理
\[ a \oplus a = 0\\0\oplus a = a \]
知道这个引理后,我们就可以看下样例
\[ a_2 \oplus a_3 \oplus a_4 \oplus (a_2 \oplus a_3) \oplus (a_3 \oplus a_4) \oplus (a_2 \oplus a_3 \oplus a_4)=a_2 \oplus a_2 \oplus a_2 \oplus a_3 \oplus a_3 \oplus a_3\oplus a_3 \oplus a_4 \oplus a_4 \oplus a_4\\=a_2\oplus0 \oplus a_4= 2 \]
也就是说我们可以根据异或的一些性质,来优化一下

如果\(a\)的个数是奇数个其贡献就是\(a\),如果\(a\)的个数是偶数个其贡献就是\(0\)

手推几个数据就能发现

如果\(l,r\)奇偶性不同所有的数都是偶数个,结果自然是\(0\)

如果\(l,r\)奇偶性相同,那么只有和\(l,r\)奇偶性的位置上的数才会有贡献

我们可以开两个树状数组来维护下,一个维护奇数位上的异或前缀和,另一个维护偶数位上的异或前缀和

对于操作1,注意不是把第\(i\)位异或\(j\)是把\(i\)为修改为\(j\),根据异或和的性质我们要先异或\(a[i]\)在异或\(j\),所以可以异或$a[i]\oplus j $

对于操作2首先特判奇偶性不同的,对于奇偶性相同的,我们在对应的树状数组里求出\(r,l-1\)的异或前缀和,在异或一下即可

#include <bits/stdc++.h>
#define lowbit( x ) ( x & - x )
using namespace std;


const int N = 2e5 + 10;
int n , m , bit[2][N] , a[N];


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

inline void add( int val , int pos , int k )
{
    for( register int i  = pos ; i <= n ; bit[k][i] ^= val , i += lowbit( i ) );
}

inline int find( int pos , int k )
{
    register int res = 0;
    for( register int i = pos ; i >= 1 ; res ^= bit[k][i] , i -= lowbit( i ) );
    return res;
}

int main()
{
    n = read() , m = read();
    for( register int i = 1  ; i <= n ; a[i] = read() , add( a[i] , i , i & 1 ) ,  i ++ );
    for( register int i = 1 , op , l , r ; i <= m ; i ++ )
    {
        op = read() , l = read() , r = read();
        if( op == 1 ) add( a[l] ^ r , l , l & 1 ) , a[l] = r ;
        else printf( "%d\n" , ( ( l + r ) & 1 ) ? 0 : ( find( r , r & 1 ) ^ find( l - 1 , r & 1 ) ) );
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Mark-X/p/11688003.html