UVA - 1598 Exchange

/*
  法一借鉴自:
  http://blog.csdn.net/xienaoban/article/details/52818530
  
  这题的特点和注意点,在上面的博客的解析中,已经说得十分详细了
*/

#include <iostream>
#include <map>
#include <set>
#include <string>
#include <vector>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;

map<int, set<int> > Buy; //映射:购买价格到购买的指令编号
map<int, int> Buy_no; //映射:购买价格到购买总量
map<int, set<int> > Sell; //映射:卖的价格到卖的指令编号
map<int, int> Sell_no;//映射:贩卖价格到贩卖总量

struct command
{
	string com;
	int num, price, id;
};

vector<command> Com; //存储指令

void Deal(int flag)
{
	//输出"TRADE"
	while (!Buy.empty() && !Sell.empty())
	{
		if (Buy.rbegin()->first >= Sell.begin()->first) //最高买价大于等于最低卖价 
		{
			set<int> &v1 = Buy.rbegin()->second; //最高买价组成的集合
			set<int> &v2 = Sell.begin()->second; //最低卖价组成的集合
			
			int num1 = *v1.begin(), num2 = *v2.begin(); //按照订单产生的先后次序,在集合中选订单产生最早的那个 
			auto &c1 = Com[num1];
			auto &c2 = Com[num2];
			int amount = min(c1.num, c2.num); //按供需取最小值交易
			c1.num -= amount;
			c2.num -= amount;
			Buy_no[c1.price] -= amount;
			Sell_no[c2.price] -= amount;
			cout << "TRADE " << amount << " " << (flag ? c1.price : c2.price) << endl;
			if (!c1.num) v1.erase(num1);
			if (!c2.num) v2.erase(num2);
			if (!Buy_no[c1.price]) Buy_no.erase(c1.price);
			if (!Sell_no[c2.price]) Sell_no.erase(c2.price); //购买 / 贩卖总量为0时,该购买 / 贩卖价格从map中删除
			if (!v1.size()) Buy.erase(c1.price);
			if (!v2.size()) Sell.erase(c2.price); 
		}
		else return;
	}
}

void Print()
{
	//输出"QUOTE"
	cout << "QUOTE ";
	if(!Buy_no.size()) cout << "0 0 - ";
	else
	{
		auto it = Buy_no.rbegin();
		cout << it->second << " " << it->first << " - ";
	}
	if (!Sell_no.size()) cout << "0 99999" << endl;
	else
	{
		auto it = Sell_no.begin();
		cout << it->second << " " << it->first << endl;
	}
}
 

int main()
{
	int kase = 0, n;
	while (cin >> n)
	{
		Buy.clear(), Buy_no.clear(), Sell.clear(), Sell_no.clear(), Com.clear();
		if (kase++) cout << endl;
		
		rep(i, n)
		{
			command temp;
			cin >> temp.com;
			if (temp.com == "BUY")
			{
				cin >> temp.num >> temp.price;
				Com.push_back(temp);
				Buy[temp.price].insert(i);
				Buy_no[temp.price] += temp.num;
				Deal(0); //"买"指令 				
			}
			else if (temp.com == "SELL")
			{
				cin >> temp.num >> temp.price;
				Com.push_back(temp);
				Sell[temp.price].insert(i); //今天发现一直一直TLE,找了很久的bug,最后发现这句代码,该写price的地方,一开始是被我写成了 num。怪不得一直一直TLE!!!这也提醒我们,细节很重要、很重要,我觉得如果真正比赛时,来一个这种错误,又一直检查不出来,心态真的会崩掉....T^T 
				Sell_no[temp.price] += temp.num;
				Deal(1); //"卖"指令 
			}
			else
			{
				int id;
				cin >> id; id--; //下标从0开始
				temp.id = id;
				Com.push_back(temp);
				auto &c = Com[id];
				int price = c.price;
				if (c.com == "BUY")
				{
					Buy[price].erase(id);
					if (Buy[price].empty()) Buy.erase(price);
					Buy_no[price] -= c.num;
					if (!Buy_no[price]) Buy_no.erase(price);
					c.num = 0;
					
				}
				else if (c.com == "SELL")
				{
					Sell[price].erase(id);
					if (Sell[price].empty()) Sell.erase(price);
					Sell_no[price] -= c.num;
					if (!Sell_no[price]) Sell_no.erase(price);
					c.num = 0;
				}
			}
			Print();
		}
	}
	return 0;
} 


/*
  法二借鉴自:
  http://blog.csdn.net/xienaoban/article/details/52818530
  
  收获:
  1. 内联函数 inline
  http://www.cnblogs.com/fnlingnzb-learner/p/6423917.html
  
  2. C++中的move,其中有两篇博客写的比较清楚详细:
  http://blog.csdn.net/booirror/article/details/24503461
  http://blog.csdn.net/liyongofdm/article/details/7667942
  
  3.STL中set的erase函数,不仅可以在set中删除某一值(见法一 v1.erase(num1); 是指删除v1集合中的元素num1),也可以在set中删除set::ieterator类型,也就是其的迭代器类型,例如:s1.erase(s1.begin());
  
  
  有个相关的博客:
  http://blog.csdn.net/s_o_q/article/details/7279508
  
*/
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
using namespace std;

struct INFO
{
	char type;
	int num, price;
}info;
string type;
vector<INFO> orders;
int N, T(0);
map<int, set<int>, greater<int> > BUY;
map<int, set<int>, less<int> > SELL;
map<int, int> BUY_SUM;
map<int, int> SELL_SUM;

void trade(bool flag)
{
	int bid_num, bid_price, ask_num, ask_price;
	while (true)
	{
		auto bid(BUY.begin()), ask(SELL.begin());
		if (bid == BUY.end()) bid_num = 0, bid_price = 0;
		else bid_num = BUY_SUM[bid->first], bid_price = bid->first;
		
		if (ask == SELL.end()) ask_num = 0, ask_price = 1e6;
		else ask_num = SELL_SUM[ask->first], ask_price = ask->first;
		
		if (bid_price < ask_price) //如果购买的最高出价,比最低售价还低,此时交易不能达成
		{
			cout << "QUOTE " << bid_num <<  " " << bid_price << " - " << ask_num << " " << (ask_price == 1e6 ? 99999 : ask_price) << endl;
			//注意此步的处理是必须做的,如果当所有的售价都已被删除(如果某一售价对应的商品数目已经全部被购买,则该售价删除),那么ask迭代器的值会是 SELL.end(),此时先将 ask_price置为一个正常情况下不可能取到的售价,在输出前,再将其变回99999
			return;
		}
		auto &c1 = orders[*bid->second.begin()], &c2 = orders[*ask->second.begin()]; //command
		auto num1 = c1.num, num2 = c2.num;
		auto amount = min(num1, num2);
		
		cout << "TRADE " << amount << " " << (flag ? ask_price : bid_price) << endl;
		
		auto &s1(bid->second), &s2(ask->second);
		BUY_SUM[bid->first] -= amount;
		if (!s1.empty() && (orders[*s1.begin()].num -= amount) == 0)
		s1.erase(s1.begin());
		if (s1.empty()) BUY.erase(bid);
		
		SELL_SUM[ask->first] -= amount;
		if (!s2.empty() && (orders[*s2.begin()].num -= amount) == 0)
		s2.erase(s2.begin());
		if (s2.empty()) SELL.erase(ask);
	}
}

int main()
{
	cin.tie(0);
	cin.sync_with_stdio(false);
	while (cin >> N)
	{
		if (T++) cout << endl;
		orders.clear(), BUY.clear(), SELL.clear(), BUY_SUM.clear(), SELL_SUM.clear();
        orders.push_back(info); //保证序号从1开始 
		for (int i = 1; i <= N; i++)
		{
			INFO temp;
			cin >> type;
			if (type[0] == 'C')
			{
				int id;
				cin >> id;
				auto& tp(orders[id]);
				if (tp.type == 'B')
				{
					BUY_SUM[tp.price] -= tp.num;
					tp.num = 0;
					auto &now (BUY[tp.price]);
					now.erase(id);
					if (now.empty()) BUY.erase(tp.price);
				}
				else
				{
					SELL_SUM[tp.price] -= tp.num;
					tp.num = 0;
					auto &now (SELL[tp.price]);
					now.erase(id);
					if (now.empty()) SELL.erase(tp.price);
				}
			}
			else
			{
				temp.type = type[0];
				cin >> temp.num >> temp.price;
				if (type[0] == 'B') BUY[temp.price].insert(i), BUY_SUM[temp.price] += temp.num;
				else SELL[temp.price].insert(i), SELL_SUM[temp.price] += temp.num;
			}
			orders.push_back(move(temp));
			trade(type[0] == 'B');
		}
	}
	return 0;
}



posted @ 2017-09-17 06:25  mofushaohua  阅读(322)  评论(0编辑  收藏  举报