HDU5892Resident Evil(二维树状数组+状态压缩)
来源:互联网 发布:java redis 获取list 编辑:程序博客网 时间:2024/06/06 18:29
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5892
题意:给定n和m表示有一个n*n的矩阵和m个操作,操作1:给出左上角的位置[x1,y1]和右下角的位置[x2,y2],然后给定k表示有k对[a,b]接下来在这个给定的矩阵中每个格子中都添加b个a类物品;操作2:给定左上角位置[x1,y1]和右下角位置[x2,y2],求所有物品在这个矩阵中的奇偶情况。
分析:
网上有很多千篇一律的题解,对于树状数组的使用都没有说的点上。
首先提醒一下,树状数组就相当于一个前缀和数组。
考虑一维情况,给一段区间[L,R]^X,然后询问一段区间内物品的奇偶性。
对于树状数组C[L..R],每个位置异或X的次数是奇、偶交错的,而异或相同的一个数偶数次等于没异或,异或相同的一个数奇数次相当于异或一次。为什么疑惑X的次数是奇、偶交错的?因为树状数组是前缀和数组,如果在区间[1, 4]内加了一个奇数x,那么普通的前缀和数组sum[1]就会加一次x,sum[2]就会加两次x,sum[3]加三次x,sum[4]加四次x。可以发现是奇、偶交错的。
第一个操作涉及二维数组的区间更新,就是说我们要把对应矩阵区域内的所有格子加上对应数量的怪物。
由于我们不需要知道对应的怪物的具体数量,只需要知道对应的怪物的数量是奇数还是偶数。所以我们
这里可以用0,1来表示对应怪物的数量是偶数还是奇数,并且我们要用到位运算异或。
在一个矩形区域内,我们要加入偶数个对应的物品,那么,无论这个矩形区域的面积是偶数还是奇数,其整个区域
内加入某种物品的个数肯定为偶数,所以是不会影响整个前缀和数组的,对于单个位置也是,因为是偶数个品,
也不会影响前缀和数组。所以对应的异或值是不会改变的。
对于加入奇数个物品的情况,由上述的奇偶交错理论,可以发现对于前缀和数组,加偶数个就是没有改变,所以
对于前缀和数组,只有x+1,x+3,x+5...等格子是毫无影响的,只有被添加到x+2,x+4,x+6...等格子,该格子的值才会变化。也就是说与前缀和数组的某个下标同奇偶的下标对应得值才会改变,不同的就不会改变。对于y的情况也是一样。再讨论下,加入奇数个物品时,加入的矩阵面积为奇数和偶数的情况,如果为奇数,那么矩矩形区域内加入的物品总数就是奇数个,对于后面的前缀和数组是有影响的,如果是偶数,那么矩阵区域内加入的物品总数就是偶数个,对于后面的前缀和数组是没有什么影响的。
实际上,加入奇数个物品,在实现上还是很难想到的。对于一个一维的树状数组,如果在[4,6]这个区间内,每个
点都加入了奇数个物品,那么这个区间内加入的物品总数也是奇数个,因为(6-4+1)*奇数 = 奇数。在进行寄偶交错的更新时,下标为4、6、8....的前缀和数组的异或值都被更改了。但因为加入的物品总是是奇数个,所以对
于下标为7、9、11的前缀和数组的异或值也需要更改。再举个例子,如果在[4,7]这个区间内,每个点都加入奇数个物品,那么这个区间内加入的物品总数是偶数个,因为(7-4+1)*奇数 = 偶数。奇偶交错的更改与上面的一个例子一样,但是因为区间内加入的物品总数也是偶数个,实际上下标为8、10、12的前缀和数组的异或值原本是不需要更改的。所以又得改回去。这边得结合代码来理解。其实这也是只对应这道题的。总之,最重要的一点就是树状数组是个前缀和数组,一切都得往这去想。
因为有50个物品,所以需要状态压缩一下。
#include<iostream>#include<algorithm>#include<cstring>#include<cstdio>using namespace std;typedef long long ll;int n, m;ll tree[2][2][3005][3005];int x1, y1, x2, y2;ll mon[55];void add(int x, int y, ll v){ for(int i = x; i <= n; i += (i&-i)) for(int j = y; j <= n; j += (j&-j)) tree[x&1][y&1][i][j] ^= v;}ll query(int x, int y){ ll res = 0; for(int i = x; i; i -= (i&-i)) for(int j = y; j; j -= (j&-j)) res ^= tree[x&1][y&1][i][j]; return res;}int main(){ char op; int x1, y1, x2, y2, k, x, y; while(scanf("%d%d", &n, &m) != EOF) { memset(tree, 0, sizeof(tree)); while(m--) { scanf(" %c%d%d%d%d", &op, &x1, &y1, &x2, &y2); if(op == 'P') { memset(mon, 0, sizeof(mon)); scanf("%d", &k); while(k--) { scanf("%d%d", &x, &y); --x; mon[x] += y; } ll temp = 0; for(int i = 0; i < 50; i++) if(mon[i] & 1) temp |= (1ll<<i); ++x2; ++y2; add(x1, y1, temp); add(x2, y2, temp); add(x1, y2, temp); add(x2, y1, temp); } else { --x1;--y1; ll temp = query(x1, y1)^query(x2, y2)^query(x1, y2)^query(x2, y1); for(int i = 0; i < 50; i++) if(temp & (1ll<<i)) printf("2 "); else printf("1 "); puts(""); } } } return 0;}
阅读全文
0 0
- HDU5892Resident Evil(二维树状数组+状态压缩)
- hdu5892 -Resident Evil 二维树状数组 + 状态压缩
- HDU5892 Resident Evil(二维树状数组+状态压缩)
- 2016 ACM/ICPC Reginal Shengyang hdu 5892 -Resident Evil 二维树状数组 + 状态压缩
- HDU 5892 Resident Evil(状态压缩+树状数组)
- hdu5892Resident Evil
- hdu 5892 沈阳网络赛 二维树状数组+状态压缩
- [HDU 5892] Resident Evil (二维树状数组)
- HDU 5892 Resident Evil(二维树状数组,好题)
- hdu5892Resident Evil(2016沈阳网络赛A)
- pku1195 二维树状数组
- 二维树状数组
- 二维树状数组
- 树状数组 二维空间
- 二维树状数组
- 二维树状数组
- 二维树状数组
- POJ2155(二维树状数组)
- Linux常用指令—awk
- 【数据结构】向STL看齐-模拟实现红黑树
- 浅谈dp px ppi dpr dpi
- 第十三章:事件类型(简述、UI事件、焦点事件)
- Linux下的exec函数
- HDU5892Resident Evil(二维树状数组+状态压缩)
- linux 查看文件系统类型
- 文章标题
- 自定义属性
- java学习(一)----正则表达式
- Mysql主从复制
- 编辑距离的一些理解
- 使用 Office 365 PowerShell 管理用户帐户和许可证(十二)Configure user account properties with Office 365 PowerShel
- kibana3 from source