Codeforces703D-Mishka and Interesting sum-离线树状数组

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:传送门

 原题目描述在最下面。
 询问一个区间内出现次数为偶数次的数字的异或和。

思路:

 先求出区间异或前缀和,其实就是出现次数为奇数次的数字的异或前缀和和。
 然后用离线树状数组树状维护区间内区间内每种数字的前缀和。
 最后的答案就是上面两个前缀和 差分一下 的异或和。

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<assert.h>
#include<bitset>
#include<unordered_map>
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x)&(-(x))
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
const int N = (int)1e6 +107;
int n, m;
LL pre[N], bit[N], ar[N], ans[N];
unordered_map<LL,int> vis;
void add(int x,LL c){
  while(x<=n){
    bit[x] ^= c;
    x += lowbit(x);
  }
}
LL query(int x){
  LL sum = 0;
  while(x){
    sum ^= bit[x];
    x -= lowbit(x);
  }
  return sum;
}
struct lp{
  int l, r, id;
}cw[N];
bool cmp(lp &a, lp &b){
  if(a.r!=b.r)return a.r<b.r;
  return a.l<b.l;
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    //freopen("E://ADpan//out.out", "w", stdout);  
#endif
  while(~scanf("%d",&n)){
    memset(pre,0,sizeof(pre));
    memset(bit,0,sizeof(bit));
    for(int i=1;i<=n;++i){
      scanf("%lld",&ar[i]);
      pre[i] = pre[i-1]^ar[i];
    }
    scanf("%d",&m);
    for(int i=0;i<m;++i){
      scanf("%d%d", &cw[i].l, &cw[i].r);
      cw[i].id = i;
    }
    sort(cw,cw+m,cmp);
    vis.clear();
    int r = 0;
    for(int i=0;i<m;++i){
      while(r<cw[i].r){
        ++r;
        add(r, ar[r]);
        if(vis[ar[r]]==0) vis[ar[r]] = r;
        else {
          add(vis[ar[r]], ar[r]);
          vis[ar[r]] = r;
        }
      }
      ans[cw[i].id]=pre[cw[i].r]^pre[cw[i].l-1]^query(cw[i].r)^query(cw[i].l-1);
    }
    for(int i=0;i<m;++i){
      printf("%lld%c", ans[i], " 
"[i==m-1]);
    }
  }
  return 0;
}

####原题目描述: ![这里写图片描述](https://img-blog.csdn.net/20180726164614519?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5NTk5MDY3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
原文地址:https://www.cnblogs.com/Cwolf9/p/9513270.html