题目描述

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. intent,实现两个活动之间数据的传递

    一.Intent 可以启动一个活动,也可以在启动活动的时候传递数据.intent中提供了putExtra()方法,它可以把我们想要传递的数据暂存在intent中,启动了另一个活动后,通过getInte ...

  2. Android中的WebView实战详解(一)

    一.为什么要用WebView? 1.兼容已有的项目2.可动态更新 二.WebView怎样使用? WebView是一个控件,如在布局中设置: <WebView android:id="@ ...

  3. ps-抠图

    1-    图层区—复制背景图层            防止原图修改失败后无法还原 2-    工具栏——磁性套索工具                    可以有效的对色彩边线较为明显的图片进行抠图 ...

  4. 用javascript动态改变网页文字大小

    <script>function setFontSize(size){document.getElementById('bottom').style.fontsize=size+'pt'; ...

  5. BootStrap入门教程 (三)

    本文转自 http://www.cnblogs.com/ventlam/archive/2012/06/05/2524966.html 上讲回顾:Bootstrap的基础CSS(Base CSS)提供 ...

  6. TreeSet集合如何保证元素唯一

    TreeSet: 1.特点 TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列 2.使用方式 a.自然顺序(Comparable) TreeSet类的add()方法中会 ...

  7. java学习笔记 --- StringBuffer类

    1.定义:字符串缓冲区,即它是一个容器,容器中可以装很多字符.并且能够对其中的字符进行各种操作. StringBuffer的特点: 1.是一个字符串缓冲区,其实就是一个容器. 2.长度是可变,任意类型 ...

  8. Office 365开发环境概览

    本文于2017年3月26日首发于LinkedIn,原文链接请参考这里 本系列文章已经按照既定计划在每周更新,此前的几篇文章如下 Office 365 开发概览系列文章和教程 Office 365开发概 ...

  9. C++实现四叉树

    什么是四叉树? 四叉树可以有效解决这个问题. 四叉树每一层都把地图划分四块,根据地图尺寸来决定树的层数,层数越大划分越细. 但需要对某一范围的单位筛选时,只需要定位到与范围相交的树区域,再对其区域内的 ...

  10. SQL Server的学习

    一.建库和表1.新建数据库语法: CREATE DATABASE SuperMarket//建立一个名为SuperMarket的数据库. 2.打开数据库语法: USE SuperMarket//打开刚 ...