1. 程式人生 > >Codeforces Round #365 (Div. 2) Problem D.Mishka and Interesting sum 解題報告

Codeforces Round #365 (Div. 2) Problem D.Mishka and Interesting sum 解題報告

題目連結:Here!

題目大意:給你n個數,然後m次查詢,每一次查詢輸出所有在給定區間內出現偶數次數的數的異或值,如果只有一個出現偶數次數的數,則直接輸出該數,如果沒有出現偶數次數的數,則輸出0。

解題思路:看到區間查詢,第一反應是線段樹,但是用線段樹來統計區間內出現次數為偶數次數的數並且儲存這些數的異或值比較麻煩。本題的1 ≤ n ≤ 1 000 000,莫隊的時間複雜度為O(n^1.5)顯然很困難,那麼我們應該怎麼做呢?首先考慮異或這個位運算的性質a  b  b=a,那我們可以很容易知道,如果一個數被異或偶數次,那麼異或結果不變。那麼一個區間內所有出現偶數次數的數的異或值就等於這個區間內所有不同數的異或值與所有出現奇數次的數異或的結果。出現奇數次的數的異或值即為這個區間內所有數的異或值,那我們只需要計算出區間內所有不同數的異或值即可。如果直接把每一個區間都遍歷一遍的話顯然時間複雜度太高,那我們把這些區間按照右端點排序,記錄每一個數上一次出現的位置(第一次出現的話就設為它自己所在的位置),然後從1-n掃一遍,把每一個掃到的數加入到樹狀陣列中,如果掃的過程中當前的數的上一次出現的位置不是當前的位置,那麼在將樹狀陣列中上一次出現的位置的影響消除,然後在當前位置插入該數。那麼,當我們每掃到一個查詢的右端點時,我們記錄下該查詢的右端點和左端點在樹狀陣列中對應的值的異或值,最後再和之前記錄過的該區間所有數的異或值異或即是答案。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <queue>
#include <stack>
#include <set>
#define LL long long
#define INF 0x3f3f3f3f
#define PII pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define INF 0x3f3f3f3f
using namespace std;
const int MAXN = 1000005 ;
int a[MAXN];//樹狀陣列
int b[MAXN];
int tot[MAXN];//陣列的字首異或值
struct Query{
    int x,y,pos,ans;
}q[MAXN];//查詢
int tt[MAXN];//記錄答案
map<int,int>Mp;
int last[MAXN];//記錄上一個相同的數出現的位置
void add(int i,int x){for(;i<=MAXN;i+=(i&-i))a[i]^=x;}
int Xor(int i){int res=0;for(;i>0;i-=(i&-i))res^=a[i];return res;}
inline bool cmp(const Query& q,const Query& w){if(q.y!=w.y)return q.y<w.y;return q.x<w.x;}

int main()
{
    int n;
    while(scanf("%d",&n)==1)
    {
        tot[0]=0;
        int cnt=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&b[i]);
            if(!Mp.count(b[i]))//離散化
                Mp[b[i]]=cnt++;
            if(last[Mp[b[i]]]==0)last[Mp[b[i]]]=i;
            tot[i]=tot[i-1]^b[i];
        }
        int m;
        scanf("%d",&m);
        for(int i=0;i<m;i++)
            scanf("%d %d",&q[i].x,&q[i].y),q[i].pos=i;
        sort(q,q+m,cmp);
        int re=0;
        for(int i=1;i<=n&&re<m;i++)
        {
            if(last[Mp[b[i]]]!=i){add(last[Mp[b[i]]],b[i]);last[Mp[b[i]]]=i;}
            add(i,b[i]);
            while(i==q[re].y&&re<m){q[re].ans=Xor(i)^Xor(q[re].x-1);re++;}
        }
        for(int i=0;i<m;i++)
            tt[q[i].pos]=q[i].ans^tot[q[i].x-1]^tot[q[i].y];
        for(int i=0;i<m;i++)
            printf("%d\n",tt[i]);
    }
    return 0;
}