CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组
2016-08-06 16:51
465 查看
题目链接:CF #365 (Div. 2) D - Mishka and Interesting sum
题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有出现偶数次的数异或的值。
思路:容易想到,把区间内的所有的数都异或得到的是出现奇数次的数的值,然后再异或该区间内的所有出现过的数(每个数只统计一次),得到的ans了。
第一个问题:得到询问区间的所有数的异或值,由 a[1~r] ^ a[0~(l-1)] = a[l~r] 可以用数组all_xor[i]保存a[1~i]区间的所有数的异或值,每次对询问区间的左右断点的all_xor值异或即可。
第二个问题:得到该区间内所有出现过的数的异或值,离线树状数组。具体操作如下:
先按照询问的右区间保存所有的询问g[r].(l, id),当前询问的结果保存在ans[id]里。
用树状数组one_xor[i]保存a[1~i]区间所有出现过的数(只统计一次)的异或值。遍历a[i],如果a[i]出现过了,对于后面的询问,右区间一定是>=i的,即i之前的区间都已经不关心这个值是否出现过了,
add_xor(mp[a[i]], a[i]),使前面的区间不再有这个数。然后mp[a[i]] = i , add_xor(mp[a[i]], a[i]) ; 这样保证了后面的每次询问都只在该最近一次出现过a[i]值的地方找到a[i]。
题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有出现偶数次的数异或的值。
思路:容易想到,把区间内的所有的数都异或得到的是出现奇数次的数的值,然后再异或该区间内的所有出现过的数(每个数只统计一次),得到的ans了。
第一个问题:得到询问区间的所有数的异或值,由 a[1~r] ^ a[0~(l-1)] = a[l~r] 可以用数组all_xor[i]保存a[1~i]区间的所有数的异或值,每次对询问区间的左右断点的all_xor值异或即可。
第二个问题:得到该区间内所有出现过的数的异或值,离线树状数组。具体操作如下:
先按照询问的右区间保存所有的询问g[r].(l, id),当前询问的结果保存在ans[id]里。
用树状数组one_xor[i]保存a[1~i]区间所有出现过的数(只统计一次)的异或值。遍历a[i],如果a[i]出现过了,对于后面的询问,右区间一定是>=i的,即i之前的区间都已经不关心这个值是否出现过了,
add_xor(mp[a[i]], a[i]),使前面的区间不再有这个数。然后mp[a[i]] = i , add_xor(mp[a[i]], a[i]) ; 这样保证了后面的每次询问都只在该最近一次出现过a[i]值的地方找到a[i]。
#include <stdio.h> #include <string.h> #include <iostream> #include <vector> #include <map> #define maxn 1000010 using namespace std; int a[maxn], one_xor[maxn], ans[maxn], all_xor[maxn]; //分别对应 原数组 (0~i)所有出现过的数的异或 保存ans (0~i)所有的数的异或 struct Query { int l, id; }; map<int, int>mp; vector<Query> query[maxn]; int n, m; void init() { mp.clear(); for (int i=1; i<=maxn; ++i) { query[i].clear(); } memset(one_xor, 0, sizeof(one_xor)); } void add_xor(int x, int val) { for (; x<=n; x+=(x&(-x))) one_xor[x] ^= val; } int sum_xor(int l, int r) { int ans = 0; for (; r>0; r-=(r&(-r))) ans ^= one_xor[r]; for (; l>0; l-=(l&(-l))) ans ^= one_xor[l]; return ans; } int main(){ //freopen("in.cpp", "r", stdin); while(~scanf("%d", &n)) { init(); all_xor[0] = 0; for (int i=1; i<=n; ++i) { scanf("%d", &a[i]); all_xor[i] = all_xor[i-1]^a[i]; } scanf("%d", &m); for (int i=1; i<=m; ++i) { int l, r; scanf("%d%d", &l, &r); query[r].push_back({l, i}); } for (int i=1; i<=n; ++i) { if (mp.count(a[i])) { add_xor(mp[a[i]], a[i]); } mp[a[i]] = i; add_xor(mp[a[i]], a[i]); for (int j=0; j<query[i].size(); ++j) { Query now = query[i][j]; ans[now.id] = (all_xor[i] ^ all_xor[now.l-1]); ans[now.id] ^= sum_xor(i, now.l-1); } } for (int i=1; i<=m; ++i) { printf("%d\n", ans[i]); } } return 0; }
相关文章推荐
- 【Codeforces Round 365 (Div 2)D】【离线询问 树状数组 前驱思想】Mishka and Interesting sum 区间内出现次数偶数的数的异或和
- Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum (离线树状数组+前缀xor)
- Codeforces Round #365 (Div. 2) D - Mishka and Interesting sum(离线树状数组)
- Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum 离线操作,树状数组,last[value],异或和
- Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum(离线树状数组)
- Codeforces Round #365 (Div. 2) Mishka and Interesting sum 树状数组
- Codeforces Round #365 (Div. 2) D.Mishka and Interesting sum (树状数组维护异或值) ★ ★
- Codeforces Round #365 (Div. 2) D Mishka and Interesting sum (离线树状数组)
- [CF#365 (Div. 2) Mishka and Interesting sum] 线段树离线处理区间不同数
- Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum(树状数组)
- Codeforces Round #365 (Div. 2)-D Mishka and Interesting sum(树状数组)
- 【codeforces 703 D】【离线询问 树状数组 前驱思想 前缀异或和】D. Mishka and Interesting sum【 区间内出现次数偶数的数的异或和】
- Codeforces Round #216 (Div. 2) E. Valera and Queries 树状数组 离线处理
- Codeforces Round #365 (Div. 2) D.Mishka and Interesting sum 树状数组+离线
- 【Codeforces Round 365 (Div 2)E】【乘除法DP map映射 约数分解】Mishka and Divisors n个数中选最小数量使得乘积为K的倍数
- HDU 4605 Magic Ball Game (dfs+离线树状数组)
- 2013 Asia Regional Contest Problem H --- Number Squence (树状数组 + 离线)
- BZOJ 1878 [SDOI2009]HH的项链——离线+树状数组||莫队算法
- codeforces CF703D Mishka and Interesting sum 树状数组
- Codeforces Round #261 (Div. 2) D. Pashmak and Parmida's problem (树状数组求逆序数 变形)