• CodeForces 339D Xenia and Bit Operations (线段树)


    题意:给定 2的 n 次方个数,对这些数两个两个的进行或运算,然后会减少一半的数,然后再进行异或运算,又少了一半,然后再进行或运算,再进行异或,不断重复,到最后只剩下一个数,要输出这个数,然后有 m 个询问,

    每个询问有 p 和 b,要求把第 p 个数改成 b,再这样运算,输出结果。

    析:这个题是不是很像线段树,不过这个题不是随机询问哪个区间,区间是固定的,这样也就简单了很多,就省下了一个query函数,再就是线段树是从上到下的,所以我们要分好到底是异或还是或,然后就很简单了,

    其实这个题也可以这样想,也是先构造一棵树,然后再考虑从下到上进行变,因为要改变值,所以先把最下面的改掉,然后再更新上去,这样次数比线段树少,比它更快一点,其实原理也是一样的。

    代码如下:

    线段树:

    #include <bits/stdc++.h>
    #define lson l,m,rt<<1,!ok
    #define rson m+1,r,rt<<1|1,!ok
    
    using namespace std;
    const int maxn = (1 << 17) + 5;
    int sum[maxn<<2];
    
    void pushup(int rt, bool ok){
        if(ok)  sum[rt] = sum[rt<<1] | sum[rt<<1|1];
        else  sum[rt] = sum[rt<<1] ^ sum[rt<<1|1];
    }
    
    void build(int l, int r, int rt, bool ok){
        if(l == r){
            scanf("%d", &sum[rt]);
            return ;
        }
        int m = (l+r) >> 1;
        build(lson);
        build(rson);
        pushup(rt, ok);
    }
    
    void update(int p, int b, int l, int r, int rt, bool ok){
        if(l == r){
            sum[rt] = b;
            return ;
        }
        int m = (l+r) >> 1;
        if(p <= m)  update(p, b, lson);
        else  update(p, b, rson);
        pushup(rt, ok);
    }
    
    int main(){
        int num, mm;
        cin >> num >> mm;
        int n = (1 << num);
        bool ok = (num & 1);
        build(1, n, 1, ok);
        while(mm--){
            int p, b;
            scanf("%d %d", &p, &b);
            update(p, b, 1, n, 1, ok);
            printf("%d
    ", sum[1]);
        }
        return 0;
    }
    

     另一种:

    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxn = (1 << 18) + 5;
    int a[maxn];
    int num;
    
    int main(){
        int n, m;
        cin >> n >> m;
        num = 1 << n;
        for(int i = 0; i < num; ++i)  scanf("%d", &a[i+num]);//构造一棵树
        int cnt = 0;
        int t = num;
        while(t){//把所有的值算一下
            t >>= 1;
            for(int i = 0; i < t; ++i)
                if(cnt & 1)   a[t+i] = a[(t+i)<<1] ^ a[(t+i)<<1|1];
                else  a[t+i] = a[(t+i)<<1] | a[(t+i)<<1|1];
            ++cnt;//控制是或还是异或
        }
    
        while(m--){
            int p, b;
            scanf("%d %d", &p, &b);
            cnt = 0;  p += num-1;
            a[p] = b;
            while(p){//从下到上更新
               p >>= 1;
               if(cnt & 1)  a[p] = a[p<<1] ^ a[p<<1|1];
               else  a[p] = a[p<<1] | a[p<<1|1];
               ++cnt;
            }
    
            printf("%d
    ", a[1]);
        }
        return 0;
    }
    
  • 相关阅读:
    Activity相关
    关于JNI接口封装(将so接口调用封装到jar包)
    在android系统源码目录下编译apk
    【原创】分享一个分析函数统计案例
    【原创】Oracle函数中对于NO_DATA_FOUND异常处理的研究
    【原创】一种维护型项目升级打包的解决方案
    【原创】如何找到Oracle中哪条记录被锁
    【原创】ORA-04068: 已丢弃程序包 的当前状态研究
    【原创】CQ数据库损坏修复
    【原创】物化视图日志对性能的影响测试
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/5653486.html
Copyright © 2020-2023  润新知