题目链接:A-咕咕东的目录管理器
题目描述:
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!
初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
现在咕咕东可以在命令行下执行以下表格中描述的命令:
Input:
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
Output:
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。
Sample Input:
1
22
MKDIR dira
CD dirb
CD dira
MKDIR a
MKDIR b
MKDIR c
CD …
MKDIR dirb
CD dirb
MKDIR x
CD …
MKDIR dirc
CD dirc
MKDIR y
CD …
SZ
LS
TREE
RM dira
TREE
UNDO
TREE
Sample Output:
OK
ERR
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
9
dira
dirb
dirc
root
dira
a
b
c
dirb
x
dirc
y
OK
root
dirb
x
dirc
y
OK
root
dira
a
b
c
dirb
x
dirc
y
Hint:
面对数据范围你要思考的是他们代表的 “命令” 执行的最大可接受复杂度,只有这样你才能知道你需要设计的是怎样复杂度的系统。
思路:
构造两个结构体,一个储存目录信息,另一个储存命令信息,同时用一个字符串数组存放使用的命令名,使用map存储边,undo前一个命令是cd,直接用命令存储的数组得到答案;如果是rm,就恢复map;mkdir就去掉map;对于tree,可以采用记录更新的方法,如果一个结构体内被标记为没有更新,就要对其进行更新;如果标记为更新,就可以直接拿来用,把要求的信息放进一个数组中,直接输出。
总结:
复杂的模拟题,做起来的感觉有点像数据结构课设了,通过课上的讲解和学长的解法代码总算弄出来了,但是如果直接看到这个题,整个人就交代了。
代码:
#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
string s;
int T,Q,op,cnt,current;
vector<pair<string,pair<int,int>>> v;
const string cmdname[]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
struct command{
string name,arg;
int type;
void initialize(string str){
name=str;
for(int i=0;i<7;i++)
if(str==cmdname[i]){
type=i;
if(i<3)
cin>>arg;
break;
}
}
}cmd;
struct directory{
string name;
map<string,int> mp;
int fa,sz;
vector<string> pre,bck;
bool tag;
void initialize(string s, int p){
tag=0,fa=p,sz=1,name=s;
pre.clear(),bck.clear(),mp.clear();
}
}node[maxn];
void update(int x,int num){
while(x!=-1){
node[x].tag=0;
node[x].sz+=num;
x=node[x].fa;
}
}
void makenode(string s,int p) {
node[++cnt].initialize(s,p);
node[p].mp[s]=cnt;
}
void mkdir(){
if(node[current].mp.count(cmd.arg)){
cout<<"ERR"<<endl;
return;
}
makenode(cmd.arg,current);
v.push_back(make_pair("MKDIR",make_pair(current,cnt)));
update(current,1);
cout<<"OK"<<endl;
}
void rm() {
if(!node[current].mp.count(cmd.arg)){
cout<<"ERR"<<endl;
return;
}
int u=node[current].mp[cmd.arg];
update(current,-node[u].sz);
v.push_back(make_pair("RM", make_pair(current,u)));
node[current].mp.erase(node[u].name);
cout<<"OK"<<endl;
}
void cd(){
if(cmd.arg==".."){
if(node[current].fa==-1){
cout<<"ERR"<<endl;
return;
}
v.push_back(make_pair("CD",make_pair(current,node[current].fa)));
current=node[current].fa;
cout<<"OK"<<endl;
return;
}
if(!node[current].mp.count(cmd.arg)){
cout<<"ERR"<<endl;
return;
}
int u = node[current].mp[cmd.arg];
v.push_back(make_pair("CD",make_pair(current,u)));
current = u;
cout<<"OK"<<endl;
}
void sz(){
cout<<node[current].sz<<endl;
}
void undo(){
if(v.size()==0){
cout<<"ERR"<<endl;
return;
}
auto t=v[v.size()-1];
v.pop_back();
cout<<"OK"<<endl;
int temp=current;
if(t.first=="MKDIR"){
cmd.name="RM";
current=t.second.first;
cmd.arg=node[t.second.second].name;
int u=node[current].mp[cmd.arg];
update(current,-node[u].sz);
node[current].mp.erase(node[u].name);
current=temp;
}
else if(t.first=="RM"){
current=t.second.first;
int u=t.second.second;
update(current,node[u].sz);
node[current].mp[node[u].name]=u;
current=temp;
}
else current=t.second.first;
}
void ls(){
int m=node[current].mp.size();
if(m==0){
cout<<"EMPTY"<<endl;
return;
}
else if(m>=1&&m<=10){
auto u=node[current].mp.begin();
while(u!=node[current].mp.end()){
cout<<u->first<<endl;
u++;
}
return;
}
else if(m>10){
auto u=node[current].mp.begin();
for(int i=1;i<=5;i++){
cout<<u->first<<endl;
u++;
}
cout<< "..."<<endl;
u=node[current].mp.end();
for(int i=1;i<=5;i++)
u--;
for(int i=1;i<=5;i++){
cout<<u->first<<endl;
u++;
}
}
}
void pushdown(int x);
void pretrack(int x){
node[x].pre.push_back(node[x].name);
if(node[x].sz==1)
return;
if(node[x].sz<=10){
for(auto i:node[x].mp){
if(!node[i.second].tag)
pushdown(i.second);
node[x].pre.insert(node[x].pre.end(),node[i.second].pre.begin(),node[i.second].pre.end());
}
return;
}
int pos=1;
for(auto i:node[x].mp){
if(!node[i.second].tag)
pushdown(i.second);
for(auto j:node[i.second].pre){
node[x].pre.push_back(j);
pos++;
if(pos>=5)
break;
}
if(pos>=5)
break;
}
}
void bcktrack(int x) {
auto it=node[x].mp.end();
it--;
int pos=0;
for(;;it--){
int u=it->second;
if(!node[u].tag)
pushdown(u);
for(int i=node[u].bck.size()-1;i>=0;i--){
node[x].bck.push_back(node[u].bck[i]);
pos++;
if(pos>=5){
reverse(node[x].bck.begin(),node[x].bck.end());
break;
}
}
if(pos>=5)
break;
if (it==node[x].mp.begin())
break;
}
}
void pushdown(int id){
node[id].pre.clear();
node[id].bck.clear();
pretrack(id);
if(node[id].sz>10)
bcktrack(id);
else
node[id].bck=node[id].pre;
node[id].tag=1;
}
void tree(){
if(!node[current].tag)
pushdown(current);
int m=node[current].sz;
if(m==1)
cout<<"EMPTY"<<endl;
else if(m>1&&m<=10){
for(int i=0;i<node[current].pre.size();i++)
cout<<node[current].pre[i]<<endl;
}
else{
for(int i=0;i<5;i++)
cout<<node[current].pre[i]<<endl;
cout<<"..."<<endl;
for(int i=5;i>=1;i--)
cout<<node[current].bck[node[current].bck.size()-i]<<endl;
}
}
int main(){
cin>>T;
while(T--){
cin>>Q;
cnt=0,current=0;
v.clear();
node[0].initialize("root", -1);
while(Q--){
cin>>s;
cmd.initialize(s);
op=cmd.type;
switch(op){
case 0:{
mkdir();
break;
}
case 1:{
rm();
break;
}
case 2:{
cd();
break;
}
case 3:{
sz();
break;
}
case 4:{
ls();
break;
}
case 5:{
tree();
break;
}
case 6:{
undo();
break;
}
}
}
}
return 0;
}