[线段树]Codeforces 339D Xenia and Bit Operations
Xenia the beginner programmer has a sequence a, consisting of 2n non-negative integers: a1, a2, ..., a2n. Xenia is currently studying bit operations. To better understand how they work, Xenia decided to calculate some value v for a.
Namely, it takes several iterations to calculate value v. At the first iteration, Xenia writes a new sequence a1 or a2, a3 or a4, ..., a2n - 1 or a2n, consisting of 2n - 1 elements. In other words, she writes down the bit-wise OR of adjacent elements of sequence a. At the second iteration, Xenia writes the bitwise exclusive OR of adjacent elements of the sequence obtained after the first iteration. At the third iteration Xenia writes the bitwise OR of the adjacent elements of the sequence obtained after the second iteration. And so on; the operations of bitwise exclusive OR and bitwise OR alternate. In the end, she obtains a sequence consisting of one element, and that element is v.
Let's consider an example. Suppose that sequence a = (1, 2, 3, 4). Then let's write down all the transformations (1, 2, 3, 4) → (1 or 2 = 3, 3 or 4 = 7) → (3 xor 7 = 4). The result is v = 4.
You are given Xenia's initial sequence. But to calculate value v for a given sequence would be too easy, so you are given additional m queries. Each query is a pair of integers p, b. Query p, b means that you need to perform the assignment ap = b. After each query, you need to print the new value v for the new sequence a.
The first line contains two integers n and m (1 ≤ n ≤ 17, 1 ≤ m ≤ 105). The next line contains 2n integers a1, a2, ..., a2n (0 ≤ ai < 230). Each of the next m lines contains queries. The i-th line contains integers pi, bi (1 ≤ pi ≤ 2n, 0 ≤ bi < 230) — the i-th query.
Print m integers — the i-th integer denotes value v for sequence a after the i-th query.
2 4
1 6 3 5
1 4
3 4
1 2
1 2
1
3
3
3
For more information on the bit operations, you can follow this link: http://en.wikipedia.org/wiki/Bitwise_operation
题意:
给出2的n次方个数,每次将现在这个序列中相邻的两个数运算后合并为一个数,得到一个新的序列,这个新序列的长度是上一个序列长度-1,当新序列长度为1时停止运算,奇数次操作进行OR运算,偶数次操作进行XOR运算,
现在有m个询问,每次询问会改变上一个序列中的一个值,问新序列运算后的值为多少
思路:
树上的每一层是一个新序列,从叶子节点那一层记为0,向上更新层数,每层的层数是它下面那层的层数+1
记录了层数之后就知道每一层要进行什么计算了,奇数层OR,偶数层XOR,
最后对每次询问单点修改,向上更新后输出根节点的值就可以了
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int amn=1<<17+5; 4 typedef long long ll; 5 int a[amn]; 6 struct tree{ 7 ll l,r,sum,deep; 8 #define ls rt<<1 9 #define rs rt<<1|1 10 #define trl tr[rt].l 11 #define trr tr[rt].r 12 #define trsum tr[rt].sum 13 #define trlssum tr[ls].sum 14 #define trrssum tr[rs].sum 15 #define trdp tr[rt].deep 16 }tr[amn]; 17 void push_up(int rt){ 18 trdp=tr[ls].deep+1; ///记录计算层数,叶子节点设为0,父节点的层数为儿子节点层数+1 19 if(trdp&1) ///奇数层数OR运算,偶数层数XOR运算 20 trsum=trlssum|trrssum; 21 else 22 trsum=trlssum^trrssum; 23 } 24 void build(int rt,int l,int r){ 25 trl=l,trr=r; 26 if(trl==trr){ 27 trsum=a[l]; 28 trdp=0; ///叶子节点计算层数 29 return ; 30 } 31 int mid=(l+r)>>1; 32 build(ls,l,mid); 33 build(rs,mid+1,r); 34 push_up(rt); 35 } 36 void updata(int rt,int l,int r,int pos,ll val){ 37 int mid=(l+r)>>1; 38 if(trl==trr&&trl==pos){ 39 trsum=val; 40 return; 41 } 42 if(pos<=mid)updata(ls,l,mid,pos,val); 43 else updata(rs,mid+1,r,pos,val); 44 push_up(rt); 45 } 46 int main(){ 47 int n,m,p,b; 48 ios::sync_with_stdio(0); 49 cin>>n>>m; 50 int len=1<<n; ///注意这里长度为2的n次方 51 for(int i=1;i<=len;i++) 52 cin>>a[i]; 53 build(1,1,len); 54 while(m--){ 55 cin>>p>>b; 56 updata(1,1,len,p,b); 57 printf("%d\n",tr[1].sum); 58 } 59 } 60 /*** 61 给出2的n次方个数,每次将现在这个序列中相邻的两个数运算后合并为一个数,得到一个新的序列,这个新序列的长度是上一个序列长度-1,当新序列长度为1时停止运算,奇数次操作进行OR运算,偶数次操作进行XOR运算, 62 现在有m个询问,每次询问会改变上一个序列中的一个值,问新序列运算后的值为多少 63 在纸上模拟可以看出这是一个完全二叉树的结构,单点修改,向上更新数值,可以想到用线段树来维护 64 树上的每一层是一个新序列,从叶子节点那一层记为0,向上更新层数,每层的层数是它下面那层的层数+1 65 记录了层数之后就知道每一层要进行什么计算了,奇数层OR,偶数层XOR, 66 最后对每次询问单点修改,向上更新后输出根节点的值就可以了 67 ***/