【题解】P9518 queue

题面传送门

解决思路

其实用链表也可以维护这样一个队列(当时感觉删人会方便点所以写了链表)。

一个比较常用的技巧是使用 stl::map,可以方便地将字符串作为下标,写起来会简单很多。

然后看懂题意模拟即可,代码里有非常详细的注释。

AC Code

//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
using namespace std;
int n;
string op,s;
string tail="0";   //队尾 
map<string,bool> pl,pd;   //分别代表一个人是否正在玩,是否正在排队 
map<string,string> fro,nxt;   //分别代表链表的前驱与后继 
vector<string> lst;   //存放上一次玩的人 

void add(string s){   //在链表的最末尾加上一个人 
	pd[s]=1;   //将此人设为正在排队 
	nxt[tail]=s,fro[s]=tail,tail=s;   //处理前驱后继,并将队尾设为当前人 
}

void del(string s){   //删人 
	pd[s]=0;   //将此人设为不在排队
	if(s==tail) tail=fro[s];   //如果此人是队尾,直接用改队尾的方法删 
	else{   //否则就是常规的链表删点 
		nxt[fro[s]]=nxt[s];   
		fro[nxt[s]]=fro[s];
	}
}

signed main(){
	IOS;TIE;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>op;
		if(op[0]=='a'){    //加人操作 
			cin>>s;
			if(pd[s]) cout<<"Error"<<'\n';    //如果此人已在队中,Error 
			else add(s),cout<<"OK"<<'\n';
		}
		else if(op[0]=='l'){    //删人操作 
			cin>>s;
			if(!pd[s]||pl[s]) cout<<"Error"<<'\n';    //如果此人不在队中或正在玩,Error 
			else del(s),cout<<"OK"<<'\n';
		}
		else if(op[0]=='s'){   //游玩操作 
			if(lst.size()){
				for(auto i:lst){    //把上一次玩的删掉,并且加入队尾 
					pl[i]=0;
					del(i),add(i);
				}
				lst.clear();
			}
			string _1=" ",_2=" ";   
			if(tail!="0"){    //尝试取第一个人 
				_1=nxt["0"];
				if(tail!=_1) _2=nxt[_1];   //尝试取第二个人 
			}
			if(_1==" ") cout<<"Error"<<'\n';    //没人 
			else if(_2==" ") cout<<_1<<'\n',lst.pb(_1),pl[_1]=1;   //有一个人 
			else cout<<_1<<' '<<_2<<'\n',lst.pb(_1),lst.pb(_2),pl[_1]=pl[_2]=1;   //有两个人
		}
	}
	return 0;
}


posted @ 2023-08-12 21:50  Binary_Lee  阅读(19)  评论(0编辑  收藏  举报
Title