CCNU 2016 个人排位赛 0 (预热)

A

将一个 Fibonacci 数拆成三个 Fibonacci 数。

fi=f0+f0+fi

B

n 个地方,去一个最近的,如果最近的地方不唯一,哪里也不去。

很简单。

C

n 个整数,可以不断任意取两个数,使得一个加一,一个减一,问多可以使得多少数相同。

操作不改变数的总和,如果总和是 n 的倍数,那么答案是 n,否则答案是 n-1。

D

n 杯一样容量,已知果汁浓度( pi )的果汁混合。求混合果汁的浓度。

答案即是 pn

E

给出一段文字,将其居中输出。

按照题意模拟即可。

F

查询一个数列的区间和,支持对区间的异或。

考察取每个数第 i 个比特位组成的 0-1 序列,维护区间和只要查询区间的 1 的个数;区间异或时,该位的序列或者不更新(异或 0),或者区间 0-1 翻转(异或 1)。照此发现可以使用线段树维护第 i 位序列的更新和查询,数据值最大有 106 ,使用 20 棵线段树维护每一位即可。

#include <stdio.h>

const int MAX_N = 1e5 + 10;

int a[MAX_N];

struct segment_tree
{
    int cnt[MAX_N << 2];
    bool flip[MAX_N << 2];

    void build(int l, int r, int id, int p)
    {
        flip[id] = false;
        if (l == r) {
            cnt[id] = ((a[l] >> p) & 1);
            return;
        }
        int m = (l + r) >> 1;
        build(l, m, id << 1, p);
        build(m + 1, r, id << 1 | 1, p);
        cnt[id] = cnt[id << 1] + cnt[id << 1 | 1];
    }

    void push_down(int l, int r, int id)
    {
        if (flip[id] && l != r) {
            int m = (l + r) >> 1;
            cnt[id << 1] = m - l + 1 - cnt[id << 1];
            cnt[id << 1 | 1] = r - m - cnt[id << 1 | 1];
            flip[id << 1] ^= 1;
            flip[id << 1 | 1] ^= 1;
            flip[id] = false;
        }
    }

    void update(int l, int r, int id, int x, int y)
    {
        push_down(l, r, id);
        if (l == x && r == y) {
            flip[id] ^= 1;
            cnt[id] = r - l + 1 - cnt[id];
            return;
        }
        int m = (l + r) >> 1;
        if (y <= m) {
            update(l, m, id << 1, x, y);
        }
        else if (x > m) {
            update(m + 1, r, id << 1 | 1, x, y);
        }
        else {
            update(l, m, id << 1, x, m);
            update(m + 1, r, id << 1 | 1, m + 1, y);
        }
        cnt[id] = cnt[id << 1] + cnt[id << 1 | 1];
    }

    int query(int l, int r, int id, int x, int y)
    {
        push_down(l, r, id);
        if (l == x && r == y) {
            return cnt[id];
        }
        int m = (l + r) >> 1;
        if (y <= m) {
            return query(l, m, id << 1, x, y);
        }
        if (x > m) {
            return query(m + 1, r, id << 1 | 1, x, y);
        }
        int ansl = query(l, m, id << 1, x, m);
        int ansr = query(m + 1, r, id << 1 | 1, m + 1, y);
        return ansl + ansr;
    }
};

const int MAX_BIT = 20;

segment_tree sgt[MAX_BIT];

int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", a + i);
    }
    for (int i = 0; i < MAX_BIT; ++i) {
        sgt[i].build(1, n, 1, i);
    }
    int m;
    scanf("%d", &m);
    for (int i = 1; i <= m; ++i) {
        int cmd;
        scanf("%d", &cmd);
        if (cmd == 1) {
            int x, y;
            scanf("%d %d", &x, &y);
            long long ans = 0;
            for (int i = 0; i < MAX_BIT; ++i) {
                ans += (long long) (1 << i) * sgt[i].query(1, n, 1, x, y); 
            }
            printf("%lld\n", ans);
        }
        else {
            int x, y, o;
            scanf("%d %d %d", &x, &y, &o);
            for (int i = 0; i < MAX_BIT; ++i) {
                if ((o >> i) & 1) {
                    sgt[i].update(1, n, 1, x, y);
                }
            }
        }
    }
    return 0;
}

posted by 张静之

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值