Consecutive Sum (利用字典树求区间异或和)

Little Jimmy is learning how to add integers. As in decimal the digits are 0 to 9, it makes a bit hard for him to understand the summation of all pair of digits. Since addition of numbers requires the knowledge of adding digits. So, his mother gave him a software that can convert a decimal integer to its binary and a binary to its corresponding decimal. So, Jimmy’s idea is to convert the numbers into binaries, and then he adds them and turns the result back to decimal using the software. It’s easy to add in binary, since you only need to know how to add (0, 0), (0, 1), (1, 0), (1, 1). Jimmy doesn’t have the idea of carry operation, so he thinks that

1 + 1 = 0

1 + 0 = 1

0 + 1 = 1

0 + 0 = 0

Using these operations, he adds the numbers in binary. So, according to his calculations,

3 (011) + 7 (111) = 4 (100)

Now you are given an array of n integers, indexed from 0 to n-1, you have to find two indices i j in the array (0 ≤ i ≤ j < n), such that the summation (according to Jimmy) of all integers between indices i and j in the array, is maximum. And you also have to find two indices, p q in the array (0 ≤ p ≤ q < n), such that the summation (according to Jimmy) of all integers between indices p and q in the array, is minimum. You only have to report the maximum and minimum integers.

Input
Input starts with an integer T (≤ 10), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 50000). The next line contains n space separated non-negative integers, denoting the integers of the given array. Each integer fits into a 32 bit signed integer.

Output
For each case, print the case number, the maximum and minimum summation that can be made using Jimmy’s addition.

Sample Input
2

5

6 8 2 4 2

5

3 8 2 6 5

Sample Output
Case 1: 14 2

Case 2: 15 1

Note
Dataset is huge, use faster I/O methods.

#include <bits/stdc++.h>
using namespace std;
const int M = 3e6 + 10;
const int inf = 0x3f3f3f3f;
int ans, ans1, ans2;
int tree[M][2];
int cnt;
void insert(int x) 
{
    int root = 0, id;
    int pos = 30;
    while (pos >= 0) 
    {
        if (x & (1 << pos))
            id = 1;
        else id = 0;
        if (tree[root][id] == 0)
        tree[root][id] = cnt++;
        root = tree[root][id];
        pos--;
    }
}
void find_max(int x) 
{
    int root = 0, id;
    int pos = 30;
    ans = 0;
    while (pos >= 0) 
    {
        if (x & (1 << pos))
            id = 1;
        else id = 0;
        if (tree[root][id ^ 1]) 
        {
            ans ^= (1 << pos);
            root = tree[root][id ^ 1];
        } 
        else root = tree[root][id];
        pos--;
    }
}
void find_min(int x) 
{
    int root = 0, id;
    int pos = 30;
    ans = 0;
    while (pos >= 0) 
    {
        if (x & (1 << pos))
            id = 0;
        else id = 1;
        if (tree[root][id ^ 1])
            root = tree[root][id ^ 1];
        else 
        {
            ans ^= (1 << pos);
            root = tree[root][id];
        }
        pos--;
    }
}
int main() 
{
    ios::sync_with_stdio(false);
    int T, i, k = 0, n, pre, a;
    cin >> T;
    while (T--) 
    {
        cin >> n;
        memset(tree, 0, sizeof(tree));
        cnt = 1, pre = 0;
        ans1 = 0, ans2 = inf;
        insert(0);
        for (i = 0; i < n; i++) 
        {
            cin >> a;
            pre ^= a;
            find_max(pre);
            ans1 = max(ans1, ans);
            find_min(pre);
            ans2 = min(ans2, ans);
            insert(pre);
        }
        printf("Case %d: %d %d\n", ++k, ans1, ans2);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值