位运算
位运算是啥?在了解位运算之前,我们要先学习一个预备知识——二进制。因为位运算是在二进制的基础上产生的。
二进制
俗话说“温故而知新,可以为师矣。” 在学习二进制之前,我们需要温习一下我们幼稚园就学到的十进制(逃。
十进制:顾名思义——满十进一。应用广泛,尤其是在幼稚园以后的生活中,无论是我们买菜还是造核武器,无论是刷高考题还是搞科研。只要有计算的地方, 80%80\%80% 都离不开十进制的运算。所以“一生二,二生三,三生万物。”并不是没有道理的(雾。
那么这又跟二进制有什么关系呢?看到了十进制的“慨念”,我们不难 yyyyyy 出二进制就是满二进一。**(好像跟生活没有太大的关系啊!)**二进制的应用主要体现在我们面前的计算机中,全世界的人都知道计算机只用一堆长长的 010101 串构成的。
那么作为一个“ OIerOIerOIer ”我们就要搞清楚二进制到底是什么!
二进制与十进制转化
(请自行百度) ororor 翻部分地区的教材(作者上学的时候是从人教版必修3(新课标版)上学到的)
二进制中一些基础的运算(位运算)
位运算的实质是将参与运算的数字转化为二进制,然后进行按位运算。
按位与(&)
运算两位全为 111 ,结果为 111 。即 111 & 1=0,11 = 0, 11=0,1 & 0=0,00 = 0, 00=0,0 & 1=0,01 = 0, 01=0,0 & 0=00 = 00=0。
例如 515151 & 5−>001100115 -> 001100115−>00110011 & 00000101=00000001−>5100000101 = 00000001 -> 5100000101=00000001−>51 & 5=15 = 15=1
特殊用法:
- 与 000 相与可清零。
- 与 111 相与可保留原值,可从一个数中取某些位。例如需要取 101011101010111010101110 中的低四位,101011101010111010101110 & 00001111=0000111000001111 = 0000111000001111=00001110,即得到所需结果。
按位或(|)
运算两位只要有一位为 111 ,其结果全为 111 。即 1∣1=1,1∣0=1,0∣1=1,0∣0=01 | 1 = 1, 1 | 0 = 1, 0 | 1 = 1, 0 | 0 = 01∣1=1,1∣0=1,0∣1=1,0∣0=0。
特殊用法:
- 与 000 相或可保留原值。
- 与 111 相或可将对应位置变为 111 。例如,将 X=10100000X = 10100000X=10100000 的低四位置 111 ,使 X∣00001111=10101111X | 00001111 = 10101111X∣00001111=10101111 即可。
异或运算(^ ororor XORXORXOR)
(作者认为就是一个不进位的加法运算)
两位为“异”,即一位为 111 一位为 000 ,则结果为 111 ,否则为 000 。即 111 ^ 1=0,11 = 0, 11=0,1 ^ 0=1,00 = 1, 00=1,0 ^ 1=1,01 = 1, 01=1,0 ^ 0=00 = 00=0。
特殊用法:
- 使指定位翻转:找一个数,对应 XXX 要翻转的各位为 111 ,其余为 000 ,使其与 XXX 进行异或运算即可。例如, X=10101110X=10101110X=10101110 ,使低四位翻转,XXX ^ 00001111=1010000100001111 = 1010000100001111=10100001 。
- 与0相异或保留原值。例如 XXX ^ 00000000=1010111000000000 = 1010111000000000=10101110 。
- 换两变量的值。(比借助容器法、加减法效率高)原理:一个数对同一个数连续两次进行异或运算,结果与这个数相等。因此,交换方法为: A=AA = AA=A ^ B,B=AB, B = AB,B=A ^ B,A=AB, A = AB,A=A ^ BBB 。
去反(~)
将一个数按位取反,即 ~ 0=1,0 = 1,0=1, ~ 1=01 = 01=0 。
左移( <<<<<< )
作者现在用到的就是 <<1<< 1<<1 等价于将数字乘以 2,<<22, << 22,<<2 等价于乘以 444 。
左移( >>>>>> )
既然 <<1<< 1<<1 是乘以 222 ,那么 >>1>> 1>>1 就是除以2。以此类推。
这样写代码会使自己代码的 BBB 格++,For Example(segment - tree):
const int maxn = 100010;
struct segmentree {
ll val, tag;
}st[maxn<<2];
inline void up(int p) {
st[p].val = st[p<<1].val + st[p<<1|1].val;
return ;
}
//p<<1 表示的是p的左儿子,p<<1|1 表示的是p的右儿子。