poj-3225
来源:互联网 发布:淘宝联盟加入购物车 编辑:程序博客网 时间:2024/06/01 17:30
// 4808K 1016MS C++#include <cstdio>#include <cstring>using namespace std;// Every node split to 2 node !!!!!!!!!!!!!!!!!!!!!!!!!!, NB trick.// e,g: 1,2 -> 12,23const int MAX = 131172;const int POS_MAX = MAX<<2;struct TreeNode { int left; int right; int color; //0: all no choosed 1: all choosed, -1: combined char rev;};typedef struct TreeNode TreeNode;TreeNode tree[MAX<<2];void buildTree(int pos, int begin, int end) { TreeNode & curNode = tree[pos]; curNode.left = begin; curNode.right = end; curNode.color = 0; curNode.rev = 0; if (begin == end) { return; } else { int mid = (begin + end)>>1; buildTree(pos<<1, begin, mid); buildTree(pos<<1|1, mid + 1, end); }}void pushDown(int pos) { TreeNode & curNode = tree[pos]; int left = curNode.left; int right = curNode.right; int color = curNode.color; char rev = curNode.rev; // printf("pushDown %d %d %d %d\n", left, right, color, rev); if (left < right) { TreeNode & leftNode = tree[pos<<1]; TreeNode & rightNode = tree[pos<<1|1]; if (color != -1) { leftNode.color = color; rightNode.color = color; curNode.color = -1; curNode.rev = 0; } if (curNode.rev) { // printf("pushDownLeft1 %d %d %d %d\n", leftNode.left, leftNode.right, // leftNode.color, leftNode.rev); if (leftNode.color != -1) { leftNode.color = (leftNode.color ? 0: 1); } else { leftNode.rev = leftNode.rev ? 0: 1; } // printf("pushDownLeft %d %d %d %d\n", leftNode.left, leftNode.right, // leftNode.color, leftNode.rev); // printf("pushDownRight1 %d %d %d %d\n", rightNode.left, rightNode.right, // rightNode.color, rightNode.rev); if (rightNode.color != -1) { rightNode.color = (rightNode.color ? 0: 1); } else { rightNode.rev = rightNode.rev ? 0: 1; } // printf("pushDownRight %d %d %d %d\n", rightNode.left, rightNode.right, // rightNode.color, rightNode.rev); curNode.rev = 0; } }}void update(int pos, int rangeLeft, int rangeRight, int choosed) { if (rangeLeft > rangeRight) { return; } TreeNode & curNode = tree[pos]; int left = curNode.left; int right = curNode.right; int color = curNode.color; if (rangeLeft <= left && rangeRight >= right) { curNode.color = choosed; curNode.rev = 0; return; // if (OP == 'B' && choosed == 0) { // curNode.color = 0; // curNode.rev = 0; // // printf("update %d %d %d %d %d\n", rangeLeft, rangeRight, left, right, curNode.color); // return; // } else if (OP == 'Y' && choosed == 1) { // curNode.color = 1; // curNode.rev = 0; // // printf("update %d %d %d %d %d\n", rangeLeft, rangeRight, left, right, curNode.color); // return; // } else if (color != -1) { // if (OP == 'B') { // curNode.color = choosed & color; // } else if (OP == 'Y') { // curNode.color = choosed | color; // } // curNode.rev = 0; // // printf("update %d %d %d %d %d\n", rangeLeft, rangeRight, left, right, curNode.color); // return; // } } pushDown(pos); int mid = (left + right)>>1; if (rangeRight <= mid) { // printf("1 %d\n", mid); // update(pos<<1, rangeLeft, rangeRight, choosed, OP); update(pos<<1, rangeLeft, rangeRight, choosed); } else if (rangeRight > mid && rangeLeft <= mid) { // printf("2 %d\n", mid); // update(pos<<1, rangeLeft, mid, choosed, OP); update(pos<<1, rangeLeft, mid, choosed); // update(pos<<1|1, mid + 1, rangeRight, choosed, OP); update(pos<<1|1, mid + 1, rangeRight, choosed); } else if (rangeLeft > mid) { // printf("3 %d\n", mid); // update(pos<<1|1, rangeLeft, rangeRight, choosed, OP); update(pos<<1|1, rangeLeft, rangeRight, choosed); }}void reverse(int pos, int rangeLeft, int rangeRight) { if (rangeLeft > rangeRight) { return; } TreeNode & curNode = tree[pos]; int left = curNode.left; int right = curNode.right; int color = curNode.color; // printf("reverse %d %d %d %d %d\n", rangeLeft, rangeRight, left, right, color); if (rangeLeft <= left && rangeRight >= right) { if (curNode.color != -1) { curNode.color = curNode.color ? 0: 1; } else { curNode.rev = curNode.rev ? 0: 1; } return; } pushDown(pos); int mid = (left + right)>>1; if (rangeRight <= mid) { reverse(pos<<1, rangeLeft, rangeRight); } else if (rangeRight > mid && rangeLeft <= mid) { reverse(pos<<1, rangeLeft, mid); reverse(pos<<1|1, mid + 1, rangeRight); } else if (rangeLeft > mid) { reverse(pos<<1|1, rangeLeft, rangeRight); }}char hash[MAX];void setHash(int pos) { if (pos > POS_MAX) { return; } TreeNode & curNode = tree[pos]; int left = curNode.left; int right = curNode.right; int color = curNode.color; // printf("setHash1 %d %d %d\n", left, right, color); if (color == 1) { // printf("setHash %d %d 1\n", left, right); for (int i = left; i<= right; i++) { hash[i] = 1; } return; } else if (color == -1) { pushDown(pos); setHash(pos<<1); setHash(pos<<1|1); }}void printFinalResult() { // printf("printFinalResult\n"); setHash(1); int begin = -1; int num = 0; for (int i = 0; i < MAX; i++) { if (hash[i]) { if (begin == -1) { // encounter a range begin // printf("printFinalResult %d\n", i); begin = i; } } else if (begin != -1) { // encouter a range end // printf("%d %d\n", begin, i-1); int left = (begin)/2 - 1; int right = (i - 1 + 1)/2 - 1; char leftBacket = begin%2 ? '(' :'['; char rightBacket = (i-1)%2 ? ')': ']'; if (num) { printf(" "); } printf("%c%d,%d%c", leftBacket, left, right, rightBacket); begin = -1; num++; } } if (!num) { printf("empty set\n"); } else { printf("\n"); }}int main() { char OPType ; char leftFlag; int left; int right; char rightFlag; char str[20]; memset(hash, 0, sizeof(hash)); buildTree(1, 0, MAX); // while(scanf("%s", str) != EOF) { while(scanf("%s %c%d,%d%c", str, &leftFlag, &left, &right, &rightFlag) != EOF) { OPType = str[0]; // while (scanf("%c %c%d,%d%c\n", &OPType, &leftFlag, &left, &right, &rightFlag) != EOF) { // printf("AAAA %d %d\n", left, right); // scanf("%c", &OPType); // scanf("%c%d,%d%c", &leftFlag, &left, &right, &rightFlag); // printf("%c %c%d,%d%c\n", OPType, leftFlag, left, right, rightFlag); left = (left+1)<<1; right = (right+1)<<1; if (leftFlag == '(') { left++; } if (rightFlag == ')') { right--; } // printf("BBBB %d %d\n", left, right); if (left > right) { // null collection, e.g: (2,2) (3,2) [3,1] if (OPType == 'I'|| OPType == 'C') { update(1, 0, MAX, 0); } continue; } switch(OPType) { case 'U': // update(1, left, right, 1, 'Y'); update(1, left, right, 1); break; case 'I': // update(1, 0, left-1, 0, 'B'); update(1, 0, left-1, 0); // update(1, right+1, MAX, 0, 'B'); update(1, right+1, MAX, 0); break; case 'D': // update(1, left, right, 0, 'B'); update(1, left, right, 0); break; case 'C': // update(1, 0, left-1, 0, 'B'); update(1, 0, left-1, 0); // update(1, right+1, MAX, 0, 'B'); update(1, right+1, MAX, 0); // printFinalResult(); reverse(1, left, right); break; case 'S': reverse(1, left, right); break; default: break; } } printFinalResult();}
终于AC了,巨纠结的一道题. 用了一种很trick的方法来表现出闭区间和开区间,即一个单位区间被拆分为3个单位区间段,
举个例子:
1到2这个区间可以表示为:
1<->2<->3, 然后就可以表示 1到2各种开闭区间的组合了: 1<->2表示 [1,2), 1<->2<->3 表示 [1,2], 2<->3表示 (1, 2], 只有一个2 则表示 (1,2)
这样就可以用线段树的点线段来表示开闭区间了(在线段树节点中加标记表示开闭区间是解决不了该问题的,必须用这种离散化的方法), 是个很有用的trick,将抽象的
开闭区间也用实际的数字表示了出来。
那么首先做的就是把输入的数字和区间开闭标记 都转化成 离散化以后的闭区间,
每个输入的区间 S<-> D,根据上面离散化的过程,有四种情况:
case1:左右都是闭区间,那么 离散化以后的是 [2S , 2D],
case2:左右都是开区间,那么离散化以后就是 [2S+1, 2D-1],
case3: 左边闭,右边开, 那么离散化以后就是 [2S, 2D-1],
case4:左边开,右边闭,那么离散化以后就是 [2S+1, 2D]
离散化以后,还要判断 是否区间是有效的,如果是无效区间(比如 (2,2) (2,1], (3,1))那么就认为其是空集。
因为离散化,数据的范围增大了一倍,因此在开线段树数组以及建树的时候要用原来数据上限 M (65536)的2倍 2M 来做。
在解决开闭区间的表示问题了以后,就要考虑如何模拟题目的5种集合操作了:
设本次操作的区间是 [l, r],之前的集合是S
(1表示该位置属于集合, 0表示该位置不属于集合)
U:把区间[l,r]覆盖成1 (很因为是并,因此只需把该区间所有位置置为1即可)
I:把[-∞,l)(r,∞]覆盖成0 (交集,[l, r]外边的所有位置置为0, 而[l, r]内的不需要改变,原来是1的,交以后还是1, 原来是0的,交以后还是0)
D:把区间[l,r]覆盖成0 (其实就是从现有的集合,去掉集合[l,r], 全部置0)
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换 (从[l, r]中去掉原来的集合,那么必然的 [l, r]之外的要全部置0, 而[l, r]内部的,原来不属于S的会属于新的集合,因此应该置为1, 而原来属于S的,要拿掉,因此要置为0, 所以就是将 [1, r]中的 1,0 对调)
S:[l,r]区间0/1互换 (只有不同时属于[l, r]和 S的才属于新的集合, 因此 [l, r]之外的必然属于新的集合,不需要改变, 而在 [l, r]内部, 原来属于S的, 这次就同时属于了[l, r]和 S, 因此要被拿掉,置为1, 而原来不属于S的,就满足了属于[l, r]而不属于S的条件,属于新的集合,因此置为1, 所有就是将[l, r]中的1, 0对调)
注意上面的区间[l, r]是离散化以后的区间,这样才能用闭区间来表示任何的原始开闭区间,才能进行上面的分析。
从上面的分析可以看出来,这次的线段树操作有两种:
一种是将整个区间置为0或1, update(l, r, v(0/1))
一种是将整个区间的0,1对调。 reverse(l, r)
而为了满足时间的需求,这两种操作都要用lazyTag的方式来表示:
一个color表示 当前区间的0或1, 同时也表示这个染色的操作被lazy在此区间, color = 0/1分别对应此区间全部为0/1以及被lazy的染色操作是0/1, 为-1时,表示该区间没有被lazy的染色操作,同时该区间是0/1混杂。
一个rev表示 该区间是否有被delay的 0/1反转操作, rev = 0/1分别表示该区间没有/有 被lazy的0/1反转操作。
在pushDown的时候,就要考虑这两个lazyTag了,
首先看是否有被lazy的染色操作,如果有,那么就将子区间染色,并继承color(和rev的继承逻辑不同,直接覆盖原来的color值), 同时将此区间的rev置为0(注意,染色表示的是一种对该区间颜色的确定,因此不需要考虑反转,这个在update的时候会被保证)。
如果没有被lazy的染色操作,就检查是否有被lazy的反转操作,如果有,那么分别检查其左右子区间,如果子区间的color不是-1,那么将子区间的color反转,否则,子区间结合自己的rev状态和父区间的rev来设置自己的rev(如果子区间本身就要反转,而父区间又下发了一个反转,那么综合以后就是两次反转,即没有变化,即不需要反转 rev设为 0,这一点很重要,当时没意识到,搞成了和color一样的逻辑,结果卡了很长时间。。。。 color == -1表示 子区间也是0/1混杂,因此不能在这一层做反转,只能等到下一层再看是否可以)。
这里把update 和 reverse分别实现了(其实两者完全可以放在一个函数)
步骤和以前的线段树操作一样,都是看当前进行操作区间是否被 update或reverse的区间覆盖,如果完全覆盖, 那么直接将该区间的color/rev设上返回即可,否则就pushDown,然后根据区间的交集情况来递归操作。
最后的收集整个集合的不相交区间也比较有意思,
要开一个flag数组H,大小是2M, 对应离散化以后的每个点, 然后对线段树进行query, 如果某个区间[l, r]的color==1,代表此区间存在集合内,就将H[l] 到 H[r]全部设为1, 如果 color == -1, 就pushDown, 然后递归查询。
最后再遍历H, 找到其上面连续为1的区间[l, r](这样就解决线段树一个连续的集合 被分割在几个线段树区间节点 不好统计的问题), 再将l 和 r反离散化得到真实的 l1 和 r1, 再根据l和r是否为偶数来决定左右区间的开闭(也是离散化的规则),输出即可。
- poj 3225
- POJ 3225
- POJ 3225
- poj 3225
- poj-3225
- poj 3225
- poj 3225(线段树)
- poj 3225(线段树)
- POJ 3225 次短路
- POJ 3225 Roadblocks
- poj 3225 区间
- POJ 3225 区间 中文
- POJ
- poj
- POJ
- POJ
- poj
- poj
- Java如何通过WSDL文件来调用这些web service
- 32位win7系统下配置IIS遇到php-cgi.exe - FastCGI 进程意外退出问题的解决办法
- poj--2524
- hdu 4941 Magical Forest (map)
- UVA434 - Matty's Blocks
- poj-3225
- 一个简单的数字记忆训练软件介绍
- (14)Android监听时return 返回的false与true的区别
- lsnrctl 中 关于status 状态的说明
- LeetCode-Maximum Subarray
- axis2 jar包详解及缺少jar包错误分析
- 【LeetCode】LRU Cache
- UITableView tableHeaderView touch
- java 中的String类