考虑一个无限完整的二叉搜索树(参见下图),节点中的数字是1,2,3,....在根节点为X的子树中,我们可以通过重复获得该子树中的最小数量沿着左边的节点往下走,直到最后一层,我们也可以通过沿着右边的节点找到最大数量。现在给出一些查询,“根节点为X的子树中的最小和最大数目是多少?” 请尝试找到有关查询的答案。
输入
在输入中,第一行包含一个整数N,表示查询的数量。在接下来的N行中,每行都包含一个代表根号为X(1 <= X <= 2 31 - 1)的子树的数字 。
产量
共有N行,其中第i行包含第i个查询的答案。
示例输入
2 8 10
示例输出
1 15 9 11
题意:求以当前为根节点下的最小值节点与最大值节点
思路:乍一看不知道是啥,但是仔细看最小节点最大节点与根节点又有些关系,最小值节点=根节点-x 最大值节点=根节点+x
但是每个对应的x值又不同,说明也与根节点的值有关系
我们就拿几个例子进行比较
我们只需要把用最小值把x求出来,最大值可以把x代进去求出
6 5 化成二进制 110 101
12 9 化成二进制 1100 1001
8 1 化成二进制 1000 0001
我们可以发现每个都是把二进制最低的1去掉再加1,然后我们求二进制最低的1有个特殊的办法 树状数组的lowbit 前不久刚学的23333
所以x=lowbit-1
那么最小值节点=x-lowbit(x)+1 最大值节点=x+lowbit(x)-1
然后这题就简单了
#include<cstdio> #include<cstring> using namespace std; int lowbit(int x) { return x&(-x); } int main() { int n,x; scanf("%d",&n); while(n--) { scanf("%d",&x); printf("%d %d ",x-lowbit(x)+1,x+lowbit(x)-1); } }
D. Xenia和位操作
每次测试的时间限制
2秒每次测试的内存限制
256兆字节输入
标准输入产量
标准输出初学者程序员Xenia有一个序列a,由2 n个非负整数组成:a 1, a 2,..., a 2 n。Xenia目前正在研究位操作。为了更好地了解他们的工作,森雅决定计算一些数值v的一个。
即,计算值v需要几次迭代。在第一次迭代中,捷尼亚写入一个新的序列一个1 或 一个2, 一个3 或 一个4,..., 一个2 Ñ - 1 或 一个2 Ñ,由2个ñ - 1元件。换句话说,她写下序列a的相邻元素的按位或。在第二次迭代中,Xenia写入了按位独占在第一次迭代之后获得的序列的相邻元素的OR。在第三次迭代中,Xenia写入在第二次迭代之后获得的序列的相邻元素的按位或。等等; 按位异或运算和按位异或运算。最后,她得到一个由一个元素组成的序列,该元素是v。
我们来看一个例子。假设序列a =(1,2,3,4)。然后让我们写下所有变换(1,2,3,4) → (1 或 2 = 3,3 或 4 = 7) → (3 xor 7 = 4)。结果是v = 4。
给你Xenia的初始序列。但是要计算给定序列的值v太容易了,所以给你额外的m个查询。每个查询都是一对整数p, b。查询p, b意味着您需要执行赋值a p = b。每次查询后,您需要为新序列a打印新值v。
输入
第一行包含两个整数Ñ和米 (1≤ Ñ ≤17,1≤ 米 ≤10 5)。下一行包含2个Ñ整数一个1, 一个2,..., 一个2 Ñ(0≤ 一个我 <2 30)。每个下一个的米线包含查询。在我个行包含整数p 我, b 我 (1个≤ p 我 ≤2 Ñ,0≤ b我 <2 30)- 第 i个查询。
产量
打印m个整数 - 第i个整数表示第i个查询后的序列a的值v。
例子
输入
复制
2 4
1 6 3 5
1 4
3 4
1 2
1 2
产量
复制
1
3
3
3
题意:输入总共2^n个数,然后让相邻的两个数进行|操作或者^操作,当是第一次的时候是|,第二次是^,这样交替进行
然后m次修改操作,这明显就是线段树的模板题,但是多了一个| ^ 的交替运算,可以判断这棵树的层数来判断是什么操作,然后发现n就是树的层数
或者用全局变量递归到最底层的时候实时更新也行
#include<cstdio> #include<cstring> #include<cmath> using namespace std; struct sss { int left; int right; int value; }mp[ ((1 << 17) + 5)<<2]; int n,m; int a[ (1 << 17) + 5]; void build(int cnt,int left,int right,int op) { mp[cnt].left=left; mp[cnt].right=right; if(left==right) { mp[cnt].value=a[left]; return ; } int mid=(left+right)/2; build(cnt<<1,left,mid,-op); build(cnt<<1|1,mid+1,right,-op); if(op==1) mp[cnt].value=mp[cnt<<1].value|mp[cnt<<1|1].value; else mp[cnt].value=mp[cnt<<1].value^mp[cnt<<1|1].value; } void updata(int cnt,int left,int right,int num,int value,int op) { if(left==right) { mp[cnt].value=value; return; } int mid=(left+right)/2; if(num<=mid) updata(cnt<<1,left,mid,num,value,-op); else updata(cnt<<1|1,mid+1,right,num,value,-op); if(op==1) mp[cnt].value=mp[cnt<<1].value|mp[cnt<<1|1].value; else mp[cnt].value=mp[cnt<<1].value^mp[cnt<<1|1].value; } int main() { scanf("%d%d",&n,&m); int t=(int)pow(2,n); for(int i=1;i<=t;i++) { scanf("%d",&a[i]); } int op; if(n&1) op=1; else op=-1; build(1,1,t,op); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); updata(1,1,t,x,y,op); printf("%d ",mp[1].value); } }