首页 > 代码库 > UVA1406 - A Sequence of Numbers(树状数组)
UVA1406 - A Sequence of Numbers(树状数组)
UVA1406 - A Sequence of Numbers(树状数组)
题目链接
题目大意:
给定N个数字,给两种操作:C x: 把这N个数字都加上x。Q x:查询这N个数里面有多少个数字和2^x取且大于0.最后把每个查询的结果求和作为答案。
解题思路:
查询与2^x取且为1,那么就意味这那个符合要求的数的第x位要是1。
但是这里还有全部加上x的操作,可以用一个变量来记录所有C操作的x的和。有这个加数的话,第x位为1的可能可以通过低位进位得到,所以这里开16个树状数组,第i个树状数组存放的是每个数从低位开始,连续的i位的值。例如7:第0个树状数组就加上1, 第1个树状数组就加上3, 第2个树状数组就加上7...
接下来要分情况讨论:首先如果加数是1XXX 那么 1) 1xxx + 0xxx = 1xxx这是符合条件的,而1xxx的范围【1000,1111】 。 2) 1xxx + 1xxx = 11xxx 这是符合条件的,11xxx的范围【11000,11111】。其次如果是 0xxx,也是分两种情况考虑,同理得到范围【1000,1111】.得到了最后符合条件的数,通过减去已知的加数,就可以求出符合查询要求的范围。在通过树状数组统计一下这个范围内的数有多少个存在。
注意:判断某个位是否位1要用&,不要单纯的判断大小。还有每个加数在对应每次查询的时候记得要取模上2^(x + 1).因为只有后面的x位是需要用的。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 7e4;
const int N = 20;
#define lowbit(x) ((x)&(-x))
typedef long long ll;
int n;
int t[N], C[N][M];
void add (int k, int x, int v) {
while (x < M) {
C[k][x] += v;
x += lowbit(x);
}
}
ll sum (int k, int x) {
int ret = 0;
while(x > 0) {
ret += C[k][x];
x -= lowbit(x);
}
return ret;
}
void init () {
t[0] = 1;
for (int i = 1; i < N; i++)
t[i] = t[i - 1] * 2;
}
void handle (int num) {
for (int i = N - 1; i >= 0; i--) {
add(i, num + 1, 1);
if (num >= t[i])
num -= t[i];
}
}
ll solve () {
ll ans = 0;
int addnum = 0;
char str[10];
int x, l, r;
while (scanf ("%s", str) && str[0] != ‘E‘) {
scanf ("%d", &x);
if (str[0] == ‘C‘)
addnum = (addnum + x) % t[16];
else {
if (addnum & t[x]) {
l = t[x + 1] + t[x] - addnum % t[x + 1];
r = min(t[x + 2] - 1 - addnum % t[x + 1], t[16] - 1);
ans += sum (x, r + 1) - sum (x, l);
}
l = t[x] - addnum % t[x + 1];
r = t[x + 1] - 1 - addnum % t[x + 1];
ans += sum (x, r + 1) - sum (x, l);
// printf("%d %d %lld\n", min, max, ans);
}
}
return ans;
}
int main () {
init();
int cas = 0, num;
while (scanf ("%d", &n) && n != -1) {
memset (C, 0, sizeof (C));
for (int i = 0; i < n; i++) {
scanf ("%d", &num);
handle(num);
}
printf ("Case %d: %lld\n", ++cas, solve());
}
return 0;
}
UVA1406 - A Sequence of Numbers(树状数组)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。