POJ 3225 线段树区间更新(经典)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Triple_WDF/article/details/82319895

题意:给定一个集合S,S为空,然后对个集合进行操作,一共有四种操作方式,分别是:

交:表示,A区间和B区间将交处。

并:表示,A区间和B区间合起来。

差集(A - B):表示在区间A而不在区间B的区间。

对称差:表示(A - B)并(B - A),在A不在B中并上在B不在A中

通过一些列的操作之后,最后得到的区间是什么,然后顺序将其输出出来,如果是空集的话就输出empty set。

想法:首先这个是个典型的线段树的问题,并且是区更新。初始态的空集S相当于一串0000000。。。这串0相当长的。然后如果一个数位在区间中被包含,我们就用1表示,如果没有在区间中就还是0。

第一个需要解决的问题:关于开区间和闭区间的问题。这里采用一个非常巧妙地方法,也就是说将原先所为的整数1,2,3,4,5,...,n。若表示区间[4, 7],非常容易,4,5,6,7,但是要表示区间(4,7)这样子就非常麻烦了,反正都是整数有一种方法就是用[3,6]表示,但是这样一来,当操作到最后,我并不能有效的将输出结果区分为开区间和闭区间,显然是和题意不符合的。那么这个时候我采用将整个区间扩大的方法来表示开区间和闭区间。例如:         [0, 0],(0, 1),[1, 1],(1, 2),[2, 2],(2, 3),[3, 3],...,(n-1, n),[n, n]。他们的标号是从0 ~ 2*n。其中奇数表示为点,也就是闭区间,偶数表示不包含整数点的区间,例如,如果要表示区间 (1,3],那么就是从(1,2)~ [3, 3]这里面的所有,也就是下标为1 * 2 + 1 ~ 3 * 2。此时就完美的将开区间和闭区间解决了,在输出的时候,例如,如果下表在3 ~ 6,那么由于3 % 2 = 1,表示是开区间,6 % 2 = 0,表示是闭区间那么他们所表示的数值分别是3 / 2 = 1,(6 + 1) / 2 = 3,不要问为啥,看着下标找规律的事情。此时,第一个问题就解决了。

第二个需要解决的问题:就是关于区间操作的问题:首先是 1.并:S <- S \cup T,将T以内的变成1即可。2.交:S <- S \cap T,将T以外的变成0,将T以内的不动。3.差:S <- S - T,将T以内的变为0;S <- T - S,将T以外变成0,T以内0,1交换。4.对称差:S <- S ⊕ T,将T中的0,1互换,这里理解非常容易,因为AB = (AB) ∪ (BA)因为这里的(AB)就相当于3中的第一个,(BA)就相当于3中的第二个,第一个和第二个合并不就是将T中的0,1互换吗!!!

第三个需要解决的问题:这基本上就是属于代码的实现问题了,小细节挺多的,比如,数据中会出现区间为空集的情况,例如[3,2],(2,2)之类的,然后数组的大小要开到符合题意稍大一点就好。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define L(x) x << 1
#define R(x) (x << 1) | 1 
using namespace std;
const int INF = 65535 * 2 + 2;
bool hash[INF];

class CSegment_Tree
{
	public:
		CSegment_Tree(int node_num);
		~CSegment_Tree()
		{
			delete[] segtree;
		} 
		void PushDown(int cur_tnode);
		void PushUp(int cur_tnode);
		void Build(int cur_tnode, int lft, int rht);
		void Updata_01(int cur_tnode, int pos_lft, int pos_rht, int val);
		void Updata_xor(int cur_tnode, int pos_lft, int pos_rht);
		void Query(int cur_tnode);
		void fuc_xor(int cur_tnode);
	private:
		struct Tree_node
		{
			int seg_lft, seg_rht;
			int ncol;
			int nxor;
			int mid()
			{
				return (seg_lft + seg_rht) >> 1;
			}
		};
		struct Tree_node *segtree;
};

CSegment_Tree::CSegment_Tree(int num_node)
{
	struct Tree_node *temp = new Tree_node[num_node * 4];
	segtree = temp;
	temp = NULL;
	delete[] temp;
}

void CSegment_Tree::Build(int cur_tnode, int lft, int rht)
{
	segtree[cur_tnode].seg_lft = lft;
	segtree[cur_tnode].seg_rht = rht;
	segtree[cur_tnode].ncol = 0;
	segtree[cur_tnode].nxor = 0;
	if(lft != rht)
	{
		int mid = segtree[cur_tnode].mid();
		Build(L(cur_tnode), lft, mid);
		Build(R(cur_tnode), mid + 1, rht); 
	}
}

void CSegment_Tree::Updata_01(int cur_tnode, int pos_lft, int pos_rht, int val)
{
	if(pos_lft > pos_rht) return; 
	int lft = segtree[cur_tnode].seg_lft;
	int rht = segtree[cur_tnode].seg_rht;
	if(pos_lft <= lft && rht <= pos_rht)
	{
		segtree[cur_tnode].ncol = val;
		segtree[cur_tnode].nxor = 0;
	}
	else
	{
		PushDown(cur_tnode);
		int mid = segtree[cur_tnode].mid();
		if(pos_lft <= mid) Updata_01(L(cur_tnode), pos_lft, pos_rht, val);
		if(pos_rht > mid) Updata_01(R(cur_tnode), pos_lft, pos_rht, val);
		PushUp(cur_tnode);
	}
}

void CSegment_Tree::Updata_xor(int cur_tnode, int pos_lft, int pos_rht)
{
	if(pos_lft > pos_rht) return;
	int lft = segtree[cur_tnode].seg_lft;
	int rht = segtree[cur_tnode].seg_rht;
	if(pos_lft <= lft && rht <= pos_rht)
	{
		fuc_xor(cur_tnode);
	}
	else
	{
		PushDown(cur_tnode);
		int mid = segtree[cur_tnode].mid();
		if(pos_lft <= mid) Updata_xor(L(cur_tnode), pos_lft, pos_rht);
		if(pos_rht > mid) Updata_xor(R(cur_tnode), pos_lft, pos_rht);
		PushUp(cur_tnode); 
	}
} 

void CSegment_Tree::Query(int cur_tnode)
{
	if(segtree[cur_tnode].ncol == 1)
	{
		for(int i = segtree[cur_tnode].seg_lft; i <= segtree[cur_tnode].seg_rht; i++)
		{
			hash[i] = true;
		}
		return;
	}
	if(segtree[cur_tnode].ncol == 0) return;
	PushDown(cur_tnode);
	Query(L(cur_tnode));
	Query(R(cur_tnode));
}

void CSegment_Tree::PushDown(int cur_tnode)
{	
	if(segtree[cur_tnode].ncol != -1)
	{
		segtree[L(cur_tnode)].ncol = segtree[R(cur_tnode)].ncol = segtree[cur_tnode].ncol; 
		segtree[L(cur_tnode)].nxor = segtree[R(cur_tnode)].nxor = 0;
	}
	
	if(segtree[cur_tnode].nxor)
	{
		segtree[cur_tnode].nxor = 0;
		fuc_xor(L(cur_tnode));
		fuc_xor(R(cur_tnode));
	}
}

void CSegment_Tree::PushUp(int cur_tnode)
{
	if(segtree[L(cur_tnode)].ncol == -1 || segtree[R(cur_tnode)].ncol == -1)
		segtree[cur_tnode].ncol = -1;
	else if(segtree[L(cur_tnode)].ncol == segtree[R(cur_tnode)].ncol)
		segtree[cur_tnode].ncol = segtree[L(cur_tnode)].ncol;
	else segtree[cur_tnode].ncol = -1;
} 

void CSegment_Tree::fuc_xor(int cur_tnode)
{
	if(segtree[cur_tnode].ncol != -1)
	{
		segtree[cur_tnode].ncol ^= 1;
		segtree[cur_tnode].nxor = 0;
	}
	else segtree[cur_tnode].nxor ^= 1;
}

int main()
{
	char op, L_flag, R_flag, key_return;
	int lft, rht;
	CSegment_Tree nseg(INF);
	nseg.Build(1, 0, INF);
	while(scanf("%c %c%d,%d%c%c", &op, &L_flag, &lft, &rht, &R_flag, &key_return) != EOF)
	{
		lft = lft * 2;
		rht = rht * 2;
		if(L_flag == '(') lft += 1;
		if(R_flag == ')') rht -= 1;
		switch(op)
		{
			case 'U':
				nseg.Updata_01(1, lft, rht, 1);
				break;
			case 'I':
				nseg.Updata_01(1, 0, lft - 1, 0);
				nseg.Updata_01(1, rht + 1, INF, 0);
				break;
			case 'D':
				nseg.Updata_01(1, lft, rht, 0);
				break;
			case 'C':
				nseg.Updata_01(1, 0, lft - 1, 0);
				nseg.Updata_01(1, rht + 1, INF, 0);
				nseg.Updata_xor(1, lft, rht);
				break;
			case 'S':
				nseg.Updata_xor(1, lft, rht);
				break;
			default:
				break;
		} 
	}
		
	memset(hash, false, sizeof(hash));
	nseg.Query(1);
	
	int st = -1, ed;
	bool find_ans = false;
	for(int i = 0; i <= INF; i++)
	{
		if(hash[i] == true)
		{
			if(st == -1) st = i;
			ed = i;
		}
		else if(st != -1)
		{
			if(find_ans) printf(" ");
			find_ans = true;
			printf("%c%d,%d%c", st % 2 == 1 ? '(' : '[', st / 2, (ed + 1) / 2, ed % 2 == 1 ? ')' : ']');
			st = -1;
		}
		
	}
	if(find_ans == false) printf("empty set");
	printf("\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Triple_WDF/article/details/82319895