题目描述

D. Mishka and Interesting sum的意思就是给出一个数组,以及若干询问,每次询问某个区间[L, R]之间所有出现过偶数次的数字的异或和。

这个东西乍看很像是经典问题,一列数字中所有数字出现偶数次,除了一个数字只出现一次,找出那个只出现过一次的数字。然而这个问题并不是要找出现奇数次数字的异或和。

算法

有一个直观的思路是求出[L, R的异或和,再异或上[L, R]之间所有出现过的数字的异或和。这样的话就可以使得数字出现次数的奇偶性发生变化。

那么怎么求出区间[L, R]所有出现过的数字的异或和呢?

先想一下如果是求区间[L, R]有多少种不同的数字怎么做?这个可以在遍历的时候保存每个数字最后出现的位置,打标记(去掉上一次的标记,更新到当前位置),去数[L, R]有多少个标记就行了。

所以求[L, R]不同数字的异或和也是类似的做法,去掉之前出现位置的标记,给当前位置打上标记,去计算[L,R]所有标记异或和。

回到原问题,有了区间不同数字的异或和,再异或上区间本身的异或值,就可以实现奇偶性翻转来得出出现偶数次的数字的异或和。

具体的流程:

需要一个异或BIT/FenwickTree,以及一个hashmap来保存元素出现位置。

按照所有询问的right值排序,遍历所有数字,每一次遍历到当前要处理的询问的R值为止。

每一步都要先往BIT中i位置加一个a[i](要做区间本身数字的异或)。

如果当前数字是第一次出现,则向BIT中i位置加一个a[i],hashmap中标记a[i]出现的位置为i。

如果当前数字之前已经出现过了,先去除上一次的标记,即向BIT中last[a[i]]加一个a[i](对于异或来说就抵消了),再向当前位置i加入一个a[i],更新hashmap中a[i]的位置为i。

可以发现,无论数字是否是第一次出现,最终hashmap中都得要给i这个位置加一个a[i],和上述每一个位置都要插入a[i]正好就抵消效果了。

所以流程可以简化为:每一步判断hashmap中是否存在a[i],存在的话取出位置值,BIT中往这个位置加a[i]。 在hashmap中插入<a[i], i>。

每一个询问的答案就是bit.query(R)^bit.query(L-1)

实现

public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
InputReader in = new InputReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
TaskD solver = new TaskD();
solver.solve(1, in, out);
out.close();
} static class TaskD {
public void solve(int testNumber, InputReader in, PrintWriter out) {
int n = in.nextInt();
long[] a = new long[n + 1];
for (int i = 1; i <= n; i++) {
a[i] = in.nextLong();
}
int m = in.nextInt();
Query[] queries = new Query[m];
for (int i = 0; i < m; i++) {
queries[i] = new Query(i, in.nextInt(), in.nextInt());
}
Arrays.sort(queries, (o1, o2) -> Integer.compare(o1.right, o2.right));
Map<Long, Integer> pos = new HashMap<>();
FenwickTree tree = new FenwickTree(n) {
@Override
protected long operate(long data, long value) {
return data ^ value;
}
@Override
public long sum(int s, int t) {
return sum(t) ^ sum(s - 1);
}
};
int i = 1;
long[] result = new long[m];
for (Query query : queries) {
for (; i <= query.right; i++) {
if (pos.containsKey(a[i])) {
tree.add(pos.get(a[i]), a[i]);
}
pos.put(a[i], i);
}
result[query.id] = tree.sum(query.left, query.right);
}
for (long ret : result) {
out.println(ret);
}
} class Query {
int id;
int left;
int right; public Query(int id, int left, int right) {
this.id = id;
this.left = left;
this.right = right;
} } } static class InputReader {
private final BufferedReader reader;
private StringTokenizer tokenizer; public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream));
tokenizer = null;
} public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
} public int nextInt() {
return Integer.parseInt(next());
} public long nextLong() {
return Long.parseLong(next());
} } static class FenwickTree {
private final long[] data; public FenwickTree(int size) {
data = new long[size + 1];
} public FenwickTree(long[] data) {
this.data = data;
} private int lowBit(int x) {
return x & -x;
} protected long operate(long data, long value) {
return data + value;
} public final void add(int p, long v) {
for (int i = p; i < data.length; i += lowBit(i)) {
data[i] = operate(data[i], v);
}
} public final long sum(int p) {
long ret = 0;
for (int i = p; i > 0; i -= lowBit(i)) {
ret = operate(ret, data[i]);
}
return ret;
} public long sum(int s, int t) {
return sum(t) - sum(s - 1);
} }
}

CF #365 703D. Mishka and Interesting sum的更多相关文章

  1. Codeforces 703D Mishka and Interesting sum 离线+树状数组

    链接 Codeforces 703D Mishka and Interesting sum 题意 求区间内数字出现次数为偶数的数的异或和 思路 区间内直接异或的话得到的是出现次数为奇数的异或和,要得到 ...

  2. codeforces 703D Mishka and Interesting sum 偶数亦或 离线+前缀树状数组

    题目传送门 题目大意:给出n个数字,m次区间询问,每一次区间询问都是询问 l 到 r 之间出现次数为偶数的数 的亦或和. 思路:偶数个相同数字亦或得到0,奇数个亦或得到本身,那么如果把一段区间暴力亦或 ...

  3. Codeforces 703D Mishka and Interesting sum(离线 + 树状数组)

    题目链接  Mishka and Interesting sum 题意  给定一个数列和$q$个询问,每次询问区间$[l, r]$中出现次数为偶数的所有数的异或和. 设区间$[l, r]$的异或和为$ ...

  4. Codeforces 703D Mishka and Interesting sum(树状数组+扫描线)

    [题目链接] http://codeforces.com/contest/703/problem/D [题目大意] 给出一个数列以及m个询问,每个询问要求求出[L,R]区间内出现次数为偶数的数的异或和 ...

  5. CodeForces 703D Mishka and Interesting sum

    异或运算性质,离线操作,区间求异或和. 直接求区间出现偶数次数的异或和并不好算,需要计算反面. 首先,很容易求解区间异或和,记为$P$. 例如下面这个序列,$P = A[1]xorA[2]xorA[3 ...

  6. CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组

    题目链接:CF #365 (Div. 2) D - Mishka and Interesting sum 题意:给出n个数和m个询问,(1 ≤ n, m ≤ 1 000 000) ,问在每个区间里所有 ...

  7. CF #365 (Div. 2) D - Mishka and Interesting sum 离线树状数组(转)

    转载自:http://www.cnblogs.com/icode-girl/p/5744409.html 题目链接:CF #365 (Div. 2) D - Mishka and Interestin ...

  8. CF #365 DIV2 D Mishka and Interesting sum 区间异或+线段树

    D. Mishka and Interesting sum time limit per test 3.5 seconds memory limit per test 256 megabytes in ...

  9. Codeforces Round #365 (Div. 2) D. Mishka and Interesting sum 离线+线段树

    题目链接: http://codeforces.com/contest/703/problem/D D. Mishka and Interesting sum time limit per test ...

随机推荐

  1. iOS回顾笔记(06) -- AutoLayout从入门到精通

    iOS回顾笔记(06) -- AutoLayout从入门到精通 随着iOS设备屏幕尺寸的增多,当下无论是纯代码开发还是Xib/StoryBoard开发,自动布局已经是必备的开发技能了. 我使用自动布局 ...

  2. multiSelect 下拉多选插件

    multiSelect是一款很好用的下拉多选插件,可以在下拉框中实现多选框,全选及取消全选等方法.使用方法:1.引用 multiSelect.css及 multiSelect.js.下载地址 http ...

  3. 剑指offer:重建二叉树

    重建二叉树的前置知识: 0.遍历二叉树: (1)前序遍历:根左右 --> 先访问根节点,再前序遍历左子树,最后前序遍历右子树: (2)中序遍历:左根右 --> 先中序遍历左子树,再访问根节 ...

  4. linux上执行 xhost unable to open display

    linux下执行xhost命令报错:unable to open display,解决方法,linux 下通过xhost进入图形界面,经常会出现报错"unable to  open disp ...

  5. [译]Selenium Python文档:二、初步开始

    2.1.简单使用 如果已经安装好了Selenium Python,你就可以像下面这样编写Python代码来使用它了: from selenium import webdriver from selen ...

  6. V3 微信支付-预支付C#

    首先不得不吐槽下腾讯,升级微信支付为毛不兼容V2版本呢?V2算是白研究了. V3预支付文档几个坑,不知道你们有没有中招 商户号 mch_id 是 String(32) 微信支付分配的商户号   其实是 ...

  7. iOS开发之应用程序启动图片规格

    一个app在启动过程中会全屏显示叫做Default.png的图片 各种规格Default的使用场合: Default.png:非retina-iPhone屏幕,320x480 Default@2x.p ...

  8. Linux云自动化运维第五课

    Linux云自动化运维第五课 一.进程定义 进程就是cpu未完成的工作 二.ps命令 ps a ###关于当前环境的所有进程 x ###与当前环境无关的所有进程 f ###显示进程从属关系 e ### ...

  9. linux命令之查看字符集

    lucifer@abc:~$ locale -a 查看本地字符集lucifer@abc:~$ locale -m 查看所有支持的字符集将文件从gb2312转为utf8iconv -f gb2312 - ...

  10. 【转】Eclipse 如何添加Android SDK

      问题描述: 如何为Eclipse编程软件添加Android SDK功能,使其能进行Android开发. 解决方法: 软件版本:Eclipse 3.7,installer_r18-windows.e ...