现在的位置: 首页 > 综合 > 正文

线段树解集合运算

2012年12月30日 ⁄ 综合 ⁄ 共 4898字 ⁄ 字号 评论关闭

线段树区间操作

                          ——集合运算

题目Help with Intervals

题目大意:给出集合的几个运算,并,交,亦或,差。集合初始为空,给出操作序列,输出最终区间。

思路:集合是有区间给出的,所以用线段树。对应操作:

                            U [a,b] 将 区间[a,b]置为1

                            I[a,b]  将区间[0,a-1],[b + 1,65536]置为0

                            D[a,b]  将区间[a,b]置为0

                            C[a,b]  将区间[0,a-1],[b + 1,65536]置为0

然后将区间[a,b]取反

                            S[a,b]  将区间[a,b]取反

         此题的特殊之处在于每次给定的区间是连续的1。这样操作起来就方便了很多

至于区间的开还是闭,只要将每个数字转化) [ ] ( 四个状态即可

提交情况:re, tl, ce, wa, ac

         原因:

1.        区间是从0开始的,不是1

2.        区间整体取反也可用延时标记

3.        注意(2,2)这种情况

4.        将一个节点置为0或1时,亦或标记应清零

收获:对于线段树来说,只要是区间整体的信息就可以用延时标记

 

AC code:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;

typedef int I64;
typedef unsigned int uI64;
typedef double real;
const double LE = log(2.0);

const uI64 Binary[32] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 
	8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 
	16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648};
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define ms(a, b) memset(a, b, sizeof(a))
#define fup(i, a, b) for(i = a; i < b; ++ i)
#define fdn(i, a, b) for(i = a; i > b; -- i)
#define inf 210000000

I64 gcd(I64 a, I64 b){ return b ? gcd(b, a % b) : a;}
I64 lcm(I64 a, I64 b){ return a / gcd(a, b) * b; }

/*
	题目:http://poj.org/problem?id=3225
	集合的并,交,亦或,差等操作。由于集合是用区间整体给出的,所以可用线段树加速
	区间修改用到了两个延时标记,一个是整体赋值的change,另一个是区间取反的Xor
*/


#define maxn 70000
const char eare[6] = ")[](";

struct interval{
	int l, r;
	interval(){ l = 0, r = 0; }
	interval(int _l, int _r) { l = _l, r = _r; }
	void init(int _l, int _r){ l = _l, r = _r; }
	interval operator * (const interval &A)const{
		return interval(max(A.l, l), min(A.r, r));
	}
};
interval eg[maxn];
int flag, sit[maxn * 4];
struct segmentTreeNode{
	int lsize, rsize, state;
	bool changed, Xor;
	segmentTreeNode* son[2];
	void init(int _lsize, int _rsize, int _state, bool _changed, segmentTreeNode* sonl, segmentTreeNode* sonr){
		lsize = _lsize, rsize = _rsize, state = _state, Xor = changed = _changed, son[0] = sonl, son[1] = sonr;
	}
	int mid(){ return (lsize + rsize) >> 1; }
};

struct segmentTree{
	segmentTreeNode *root, * link;
	int ad;
	segmentTree(){
		ad = 0;
		link = new segmentTreeNode[maxn * 16];
	}
	~segmentTree(){
		delete[] link;
	}
	void built(int l, int r, segmentTreeNode* &rt){
		rt = &link[ad ++];
		rt->init(l, r, 0, 0, NULL, NULL);
		if(l == r) return;
		built(l, rt->mid(), rt->son[0]);
		built(rt->mid() + 1, r, rt->son[1]);
	}
	/* 改变区间值 */
	void renew(segmentTreeNode* &rt, int sate){
		if(rt == NULL || rt->state == sate) return;
		rt->changed ^= 1;
		rt->Xor = 0;
		rt->state = sate;
	}
	/* 改变亦或延迟标记 */
	void rexor(segmentTreeNode* &rt){
		if(rt->state != -1){
			rt->changed ^= 1;
			rt->state ^= 1;
			return;
		}
		rt->Xor ^= 1;

	}
	/* 延迟标记向下传递 */
	void down(segmentTreeNode* &rt){
		if(rt == NULL) return;
		if(rt->Xor){
			rt->Xor = 0;
			rexor(rt->son[0]);
			rexor(rt->son[1]);
			return;
		}
		if(rt->state == -1) return;
		renew(rt->son[0], rt->state);
		renew(rt->son[1], rt->state);
		rt->state = -1;
		rt->changed = 0;
	}
	/* 将区间l到r置为sate */ 
	void update(int l, int r, int sate, segmentTreeNode* rt){
		if(l > r) return;
		if(l == rt->lsize && r == rt->rsize){
			renew(rt, sate);
			return;
		}
		down(rt);
		if(l > rt->mid()) update(l, r, sate, rt->son[1]);
		else{
			if(r <= rt->mid()) update(l, r, sate, rt->son[0]);
			else{
				update(l, rt->mid(), sate, rt->son[0]);
				update(rt->mid() + 1, r, sate, rt->son[1]);
			}
		}
		if(rt->son[0]->state == rt->son[1]->state){
			rt->state = rt->son[0]->state;
		}
	}
	/* 将区间l,r取反 */
	void negate(int l, int r, segmentTreeNode* rt){
		if(rt == NULL || l > r) return;
		if(l == rt->lsize && r == rt->rsize){
			rexor(rt);
			return;
		}
		down(rt);
		if(l > rt->mid()) negate(l, r, rt->son[1]);
		else{
			if(r <= rt->mid()) negate(l, r, rt->son[0]);
			else{
				negate(l, rt->mid(), rt->son[0]);
				negate(rt->mid() + 1, r, rt->son[1]);
			}
		}
		if(rt->son[0]->state == rt->son[1]->state){
			rt->state = rt->son[0]->state;
		}
	}
	/* 输出区间 */
	void out(segmentTreeNode* rt){
		if(rt == NULL) return;
		if(rt->state != -1){
			if(rt->state == 1) {
				for(int i = rt->lsize; i <= rt->rsize; ++ i) sit[i] = 1;
			}
			return;
		}
		down(rt);
		out(rt->son[0]);
		out(rt->son[1]);
	}
};

const int n = 65536;

int reget(int x, char od){
	x *= 4;
	if(od == '(') return x + 3;
	if(od == ')') return x + 0;
	if(od == '[') return x + 1;
	if(od == ']') return x + 2;
}

int main(){
	char ord[3], l[2], r[2], ch[2];
	int x, y;
	segmentTree seg;
	seg.built(0, (n + 1) * 4, seg.root);
	while(~scanf("%1s %1s %d %1s %d %1s", ord, l, &x, ch, &y, r)){
		switch(ord[0]){
		case 'U' :
			x = reget(x, l[0]);
			y = reget(y, r[0]);
			if(x > y) continue;
			seg.update(x, y, 1, seg.root);
			break;
		case 'I' :
			x = reget(x, l[0]);
			y = reget(y, r[0]);
			if(x > y){
				seg.update(0, (n + 1) * 4, 0, seg.root);
				continue;
			}
			seg.update(reget(0, '['), x - 1, 0, seg.root);
			seg.update(y + 1, reget(n, ']'), 0, seg.root);
			break;
		case 'D' :
			x = reget(x, l[0]);
			y = reget(y, r[0]);
			if(x > y) continue;
			seg.update(x, y, 0, seg.root);
			break;
		case 'C' :
			x = reget(x, l[0]);
			y = reget(y, r[0]);
			if(x > y){
				seg.update(0, (n + 1) * 4, 0, seg.root);
				continue;
			}
			seg.update(reget(0, '['), x - 1, 0, seg.root);
			seg.update(y + 1, reget(n, ']'), 0, seg.root);
			seg.negate(x, y, seg.root);
			break;
		case 'S' :
			x = reget(x, l[0]);
			y = reget(y, r[0]);
			if(x > y) continue;
			seg.negate(x, y, seg.root);
			break;
		}
	}
	flag = 0;
	seg.out(seg.root);
	x = -1;
	for(int i = 0; i < maxn * 4; ++ i){
		if(x == -1 && sit[i] == 1) x = i;
		if(sit[i] == 0 && x != -1){
			if(flag) printf(" ");
			printf("%c%d,%d%c", eare[x % 4], x / 4, (i - 1) / 4, eare[(i - 1) % 4]);
			flag = 1;
			x = -1;
		}
	}
	if(!flag) printf("empty set\n");
	else printf("\n");
	return 0;
}

抱歉!评论已关闭.