gryz校赛 或和异或

· · 个人记录

问题描述

loceaner 最近在研究位运算,它研究的主要有两个:or 和 xor。 (C 语言中对于 | 和∧)￿

为了更好的了解这两个运算符,loceaner 找来了一个 2 ^n 长度的数组。它第一次先对所有相邻两个 数执行 or 操作,得到一个 2^n−1 长度的数组。也就是说,一开始时数组为 a[1],a[2],…,a[2 n ],

执行完第 一次操作后,会得到 a[1] or a[2],a[3] or a[4],…,a[2 n − 1] or a[2 n ]。

第二次操作,loceaner 会将所有相邻两个数执行 xor 操作,得到一个 2 n−2 长度的数组,假如第一 次操作后的数组是 b[1],b[2],⋯,b[2 n−1 ],那么执行完这次操作后会变成 b[1] xor b[2], b[3] xor b[4] ,⋯, b[2 n−1 − 1] xor b[2 n−1 ]。

第三次操作,loceaner 仍然将执行 or 操作,

第四次 loceaner 执行 xor 操作。如此交替进行。

最终这 2 n 个数一定会变成 1 个数。loceaner 想知道最终这个数是多少。 为了让这个游戏更好玩,loceaner 还会执行 Q 次修改操作。每次修改原先的 2 n 长度的数组中的

某一个数,对于每次修改操作,你需要输出 n 次操作后(最后一定只剩下唯一一个数)剩下的那个数 是多少。

输入

第一行两个数 n ,Q。

接下来一行 2 n 个数 a i 表示一开始的数组。

接下来 Q 行,每行两个数 x i ,y i ,表示 loceaner 这次的修改操作是将 a[x i ] 改成 y i 。

输出

Q 行,表示每次修改操作后执行 n 次操作后剩下的那个数的值。

思路

符合线段树的性质,两个合为一个,然后一直往上合,所以直接套用线段树进行解决

解法

#include<iostream>
#include<cstdio>
#include<cstring> 
#include<queue>
#include<cmath>
#define rson rt<<1|1
#define lson rt<<1
#define N 200010 
using namespace std;
int n,m;
struct node{
    int sum;
    int len; 
}tree[N<<2];
void push_up(int rt)
{
    double x=log(tree[rt].len)/log(2);
    int dep=x;
    if(dep%2==1) tree[rt].sum=(tree[lson].sum|tree[rson].sum);
    else tree[rt].sum=(tree[lson].sum^tree[rson].sum);
}
void build(int rt,int l,int r)
{
    tree[rt].len=r-l+1;
    if(l==r)
    {
        cin>>tree[rt].sum;
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(rt);
}
void update(int rt,int val,int l,int r,int pow)
{
    if(l==r)
    {
        tree[rt].sum=val;
        return;
    }
    int mid=(l+r)>>1;
    if(pow<=mid) update(lson,val,l,mid,pow);
    else update(rson,val,mid+1,r,pow);
    push_up(rt); 
}
int main()
{
    cin>>n>>m;
    n=(1<<n);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        update(1,y,1,n,x);//从1节点开始向下修改x号点的值为y,
        cout<<tree[1].sum<<endl; 
    } 
    return 0;
}