【洛谷P6225】异或橙子
期中刚考完就过来接着学算法啦
毕竟oop那堆东西基本上放到开发工程效率提高才比较明显,放到这里其实就不大行了
那么,我们今天还是看一道树状数组的题目,明天开始学习线段树
奇怪。这些东西当年我不是都会吗
P6225 [eJOI 2019] 异或橙子
题目描述
Janez 喜欢橙子!他制造了一个橙子扫描仪,但是这个扫描仪对于扫描的每个橙子的图像只能输出一个 \(32\) 位整数。
他一共扫描了 \(n\) 个橙子,但有时他也会重新扫描一个橙子,导致这个橙子的 \(32\) 位整数发生更新。
Janez 想要分析这些橙子,他觉得异或操作非常有趣,他每次选取一个区间从 \(l\) 至 \(u\),他想要得到这个区间内所有子区间的异或和的异或和。
例如 \(l=2,u=4\) 的情况,记橙子序列 \(A\) 中第 \(i\) 个橙子的整数是 \(a_i\),那么他要求的就是:
注:式子中的 \(\oplus\) 代表按位异或运算。异或的运算规则如下。
对于两个数的第 \(i\) 位,记为 \(x,y\),那么:
| \(x\) | \(y\) | \(x\oplus y\) |
|---|---|---|
| \(0\) | \(1\) | \(1\) |
| \(1\) | \(0\) | \(1\) |
| \(0\) | \(0\) | \(0\) |
| \(1\) | \(1\) | \(0\) |
例:\(13\oplus 23=26\)
| \(13=\) | \(0\cdots 001101\) |
|---|---|
| \(23=\) | \(0\cdots 010111\) |
| \(13\oplus 23=\) | \(0\cdots 011010\) |
输入格式
第一行输入两个正整数 \(n,q\),表示橙子数量和操作次数。
接下来一行 \(n\) 个非负整数,表示每个橙子扫描得到的数值 ,从 \(1\) 开始编号。
接下来 \(q\) 行,每行三个数:
-
如果第一个数是 \(1\),接下来输入一个正整数 \(i\) 与非负整数 \(j\),表示将第 \(i\) 个橙子的扫描值 \(a_i\) 修改为 \(j\)。
-
如果第一个数是 \(2\),接下来输入两个正整数 \(u,l\) 表示询问这个区间的答案。
输出格式
对于每组询问,输出一行一个非负整数,表示所求的总异或和。
输入输出样例 #1
输入 #1
3 3
1 2 3
2 1 3
1 1 3
2 1 3
输出 #1
2
0
输入输出样例 #2
输入 #2
5 6
1 2 3 4 5
2 1 3
1 1 3
2 1 5
2 4 4
1 1 1
2 4 4
输出 #2
2
5
4
4
说明/提示
输入输出样例 1 解释
-
最初,\(A=[1,2,3]\),询问结果为 \(1\oplus 2\oplus 3\oplus(1\oplus 2)\oplus (2\oplus 3)\oplus(1\oplus 2\oplus 3)=2\)
-
修改后,第一个位置被修改为 \(3\) ,询问的结果是 \(3\oplus 2\oplus 3\oplus(3\oplus 2)\oplus (2\oplus 3)\oplus(3\oplus 2\oplus 3)=0\)。
数据规模与约定:
本题采用多测试点捆绑测试,共有 5 个子任务。
- Subtask 1(12 points):\(1\le n,q\le 10^2\),无特殊限制
- Subtask 2(18 points):\(1\le n,q\le 5\times 10^2\),且没有修改操作。
- Subtask 3(25 points):\(1\le n,q\le 5\times 10^3\),无特殊限制
- Subtask 4(20 points):\(1\le n,q\le 2\times 10^5\),且没有修改操作。
- Subtask 5(25 points):\(1\le n,q\le 2\times 10^5\),无特殊限制
对于所有数据,\(0\le a_i\le 10^9,1\le n,q\le 2\times 10^5\)
说明
原题来自:eJOI2019 Problem A. XORanges
题面&数据来自:LibreOJ
解法&&个人感想
其实这道题我还是看了洛谷题解的
虽然数学原理自己推出来了,但是实现上出了问题
不过,这道题还是可以让我们学会很多关于异或的知识
首先,我们知道了异或是符合交换律和结合律的,所以任意的括号都可以打开
现在,我们考虑一个数列\(a_1,a_2\ldots a_m\),对其求任意子区间的异或和,我们可以计算出,对于\(a_i\),其在这个表达式中出现了\(i(m-i+1)\)次,由于异或的偶数变0性,我们可以推出,当\(m,i\)均为奇数的时候,原式可以计算
这个时候怎么办呢?我们可以维护奇数和偶数分别两个树状数组,然后对其求异或和,就可以
而且不必加一堆繁文缛节,还可能导致出错,因为原来的函数其实某种意义上说,对不必要的数异或,并没有什么影响(因为0异或任何数,还是它本身)。
有一个小细节,就是我们在update的时候,原数组也要跟着变,因为我们有的操作是依托原数组的数完成的,就比如当更新异或值的时候,如果连续更新两次同一下标的元素,但是原数组却没有变的话,就会出问题了
下面看代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x&(-x))
#define maxn 200005
using namespace std;
int ma[maxn];
int n,q;
int op,a,b;
int oddtree[maxn];//奇数
int eventree[maxn];//偶数
void update_1(int a,int b){
for(;a<=n;a+=lowbit(a)) eventree[a]^=b;
return ;
}
void update_2(int a,int b){
for(;a<=n;a+=lowbit(a)) oddtree[a]^=b;
return ;
}
int query_1(int x){
int ans=0;
for(;x;x-=lowbit(x)) ans^=eventree[x];
return ans;
}
int query_2(int x){
int ans=0;
for(;x;x-=lowbit(x)) ans^=oddtree[x];
return ans;
}
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++){
cin>>ma[i];
if(i%2) update_2(i,ma[i]);
else update_1(i,ma[i]);
}
for(int i=1;i<=q;i++){
cin>>op;
if(op==1){
cin>>a>>b;
if(a%2==0){
update_1(a,ma[a]^b);
ma[a]=b;
}
else{
update_2(a,ma[a]^b);
ma[a]=b;
}
}
else{
cin>>a>>b;
if((b-a)%2==1){
cout<<0<<endl;
continue;
}
else{
if(a%2==0){
int ans_2=query_1(b);
int ans_1=query_1(a-1);
int temp=ans_2^ans_1;
cout<<temp<<endl;
}
else{
int ans_2=query_2(b);
int ans_1=query_2(a-1);
int temp=ans_2^ans_1;
cout<<temp<<endl;
}
}
}
}
system("pause");
return 0;
}
最近换壁纸啦!Charlotte的ED几张静态图真的绝美,还是8K的,用PS提一下亮度之后手上的Wallpaper Engine 顿时就不香了
后半学期,也请各位继续关注:
《我的青春线代物语果然有问题》
《高数女主养成计划》
《程设の旅》
《青春猪头少年不会梦到多智能体吃豆人》
《某Linux的开源软件》
新增:《Charlotte太空探索》(最符合学科内容的一集,Charlotte彗星怎么不是一种太空探索呢)
还有——
《我的算法竞赛不可能这么可爱》
本期到此结束!

浙公网安备 33010602011771号