POJ 2777 解题报告

这道题看着就是segment tree的题,但是trick的地方很多。

首先是颜色的表示。用int数组的话粗略计算了下感觉会超内存,于是用的是set<int>,可以想到,这使得速度降低了很多。看到discuss上面一个同学说的才恍然大悟,因为color的数目不大于30,所以一个32位int就绰绰有余,而且int的位运算天然地就比set简单快捷。

其次是lazy update。我其实不是很清楚这个有多大影响,不过应该很重要。

再次是POJ的一些特性,g++的时候过不了,改成c++就以900+ms过了。然后将cin, cout改成scanf,printf就有了现在360ms的程序。

2777Accepted3268K360MSC++3762B
/* 
ID: thestor1 
LANG: C++ 
TASK: poj2777 
*/
#include <iostream>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <limits>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <algorithm>
#include <cassert>

using namespace std;

class Node
{
public:
	// as the number of different colors is less than 30, a single int should be sufficient
	int colors;
	bool delay;	
	Node() : colors(0), delay(false) {}
};

void update(vector<Node> &segmentTree, int left, int right, int index, const int lindex, const int rindex, const int color)
{	
	if (lindex <= left && right <= rindex)
	{
		segmentTree[index].colors = (1 << color);
		segmentTree[index].delay = true;
		return;
	}

	if (left != right)
	{
		int mid = left + ((right - left) >> 1);
		if (segmentTree[index].delay)
		{
			segmentTree[2 * index + 1].colors = segmentTree[index].colors;
			segmentTree[2 * index + 1].delay = true;
			segmentTree[2 * index + 2].colors = segmentTree[index].colors;
			segmentTree[2 * index + 2].delay = true;
			segmentTree[index].delay = false;
		}

		if (rindex <= mid)
		{
			update(segmentTree, left, mid, 2 * index + 1, lindex, rindex, color);
		}
		else if (lindex >= mid + 1)
		{
			update(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex, color);
		}
		else
		{
			update(segmentTree, left, mid, 2 * index + 1, lindex, rindex, color);
			update(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex, color);		
		}

		segmentTree[index].colors = segmentTree[2 * index + 1].colors | segmentTree[2 * index + 2].colors;
	}
}

void query(vector<Node> &segmentTree, int left, int right, int index, const int lindex, const int rindex, int &colors)
{
	if (lindex <= left && right <= rindex)
	{
		colors |= segmentTree[index].colors;
		return;
	}

	if (left != right)
	{
		int mid = left + ((right - left) >> 1);
		if (segmentTree[index].delay)
		{
			segmentTree[2 * index + 1].colors = segmentTree[index].colors;
			segmentTree[2 * index + 1].delay = true;
			segmentTree[2 * index + 2].colors = segmentTree[index].colors;
			segmentTree[2 * index + 2].delay = true;
			segmentTree[index].delay = false;
		}

		if (rindex <= mid)
		{
			query(segmentTree, left, mid, 2 * index + 1, lindex, rindex, colors);
		}
		else if (lindex >= mid + 1)
		{
			query(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex, colors);
		}
		else
		{
			query(segmentTree, left, mid, 2 * index + 1, lindex, rindex, colors);
			query(segmentTree, mid + 1, right, 2 * index + 2, lindex, rindex, colors);		
		}
	}
}


int cntcolors(int colors)
{
	int cnt = 0;
	while (colors)
	{
		colors &= colors - 1;
		cnt++;
	}
	return cnt;
}

int main()
{
	int L, T, O;
	// cin >> L >> T >> O;
	scanf("%d%d%d", &L, &T, &O);
	// cout << "L:" << L << ", T: " << T << ", O: " << O << endl;
	vector<Node> segmentTree(4 * L);
	update(segmentTree, 0, L - 1, 0, 0, L - 1, 0);

	char type;
	int a, b, c;

	for (int t = 0; t < O; ++t)
	{
		// cin >> type >> a >> b;
		type = 'A';
		while (type != 'C' && type != 'P')
		{
			scanf("%c", &type);
		}

		scanf("%d%d", &a, &b);
		a--, b--;
		if (a > b)
		{
			int tmp = a;
			a = b;
			b = tmp;
		}

		if (type == 'C')
		{
			// color
			// cin >> c;
			scanf("%d", &c);
			c--;
			update(segmentTree, 0, L - 1, 0, a, b, c);
		}
		else
		{
			// print
			int colors = 0;
			query(segmentTree, 0, L - 1, 0, a, b, colors);
			
			// cout << "[debug]colors: " << colors << endl;
			// cout << cntcolors(colors) << endl;
			printf("%d\n", cntcolors(colors));
		}
	}

	return 0;  
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值