首页 > 代码库 > UVA 1406 - A Sequence of Numbers(树状数组)

UVA 1406 - A Sequence of Numbers(树状数组)

UVA 1406 - A Sequence of Numbers

题目链接

题意:给定一些数字,每次操作
C x 表示所有数字加上x
Q x 表示答案加上与2x进行且操作不为0的个数
E 结束,并输出答案

思路:树状数组,首先观察,对于每次查询x而言,只有前x位是是有用的,所以可以开16个树状数组,每个数组表示数字对应前x位下的数字,然后就可以搞了,已经现在加过值为sum,可以推出
2x<=sum+num<2x,这样就可以根据sum来推出num的相应区间,利用区间查询进行查找

代码:

#include <cstdio>
#include <cstring>

#define lowbit(x) (x&(-x))
const int N = 66666;

typedef long long ll;

int n, bit[16][N], mi[20];

void add(int i, int x, int v) {
    while (x < N) {
	bit[i][x] += v;
	x += lowbit(x);
    }
}

int get(int i, int x) {
    int ans = 0;
    while (x) {
	ans += bit[i][x];
	x -= lowbit(x);
    }
    return ans;
}

void init() {
    memset(bit, 0, sizeof(bit));
    int num;
    while (n--) {
	scanf("%d", &num);
	for (int i = 1; i <= 16; i++) {
	    add(i - 1, num % mi[i] + 1, 1);
	}
    }
}

ll solve() {
    char op[2];
    int d, sum = 0;
    ll ans = 0;
    while (scanf("%s", op)) {
	if (op[0] == 'E') break;
	scanf("%d", &d);
	if (op[0] == 'C')
	    sum = (sum + d) % mi[16];
	else {
	    int tmp = sum % mi[d];
	    if (sum&mi[d])
		ans += get(d, mi[d] - tmp) + get(d, mi[d + 1]) - get(d, mi[d + 1] - tmp);
	    else ans += get(d, mi[d + 1] - tmp) - get(d, mi[d] - tmp);
	}
    }
    return ans;
}

int main() {
    int cas = 0;
    mi[0] = 1;
    for (int i = 1; i <= 16; i++)
	mi[i] = mi[i - 1] * 2;
    while (~scanf("%d", &n) && n != -1) {
	init();
	printf("Case %d: %lld\n", ++cas, solve());
    }
    return 0;
}