zoukankan      html  css  js  c++  java
  • 区间出现偶数次的数的异或和

    题目描述

    初始给定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
    " , ans[i]) ;
        return 0 ;
    }	
    
  • 相关阅读:
    关于通过web页面删除数据记录的设计改进
    python 正则表达式用法
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
  • 原文地址:https://www.cnblogs.com/Stephen-F/p/10951791.html
Copyright © 2011-2022 走看看