题目描述:
咕咕东的雪梨电脑的操作系统在上个月受到宇宙射线的影响,时不时发生故障,他受不了了,想要写一个高效易用零bug的操作系统 —— 这工程量太大了,所以他定了一个小目标,从实现一个目录管理器开始。前些日子,东东的电脑终于因为过度收到宇宙射线的影响而宕机,无法写代码。他的好友TT正忙着在B站看猫片,另一位好友瑞神正忙着打守望先锋。现在只有你能帮助东东!
初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root
。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
实现 | 说明 | |
MKDIR s | 在当前目录下创建一个子目录s,是一个字符串 | 创建成功输出 "OK";若当前目录下已有该子目录则输出 "ERR" |
RM s | 在当前目录下删除子目录 s,s 是一个字符串 | 删除成功输出 "OK";若当前目录下该子目录不存在则输出 "ERR" |
CD s | 进入一个子目录 s,s 是一个字符串(执行后,当前目录可能会改变) | 进入成功输出 "OK";若当前目录下该子目录不存在则输出 "ERR" 特殊地,若 s 等于 ".." 则表示返回上级目录,同理,返回成功输出 “OK”,返回失败(当前目录已是根目录没有上级目录)则输出 “ERR” |
SZ | 输出当前目录的大小 | 也即输出 1+当前目录的子目录数 |
LS | 输出多行表示当前目录的 "直接子目录" 名 | 若没有子目录,则输出 “EMPTY”;若子目录数属于 [1,10] 则全部输出;若子目录数大于 10,则输出前 5 个,再输出一行"…",输出后 5 个。 |
TREE | 输出多行表示以当前目录为根的子树的前序遍历结果 | 若没有后代目录,则输出 “EMPTY”;若后代目录数+1(当前目录)属于 [1,10] 则全部输出;若后代目录数+1(当前目录)大于 10,则输出前 5 个,再输出一行 “…”,输出后 5 个。 |
UNDO | 撤销操作 | 撤销最近一个 “成功执行” 的操作(即MKDIR或RM或CD)的影响,撤销成功输出 “YES” 失败或者没有操作用于撤销则输出 “ERR” |
文末附英文题目
input:
输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);
output:
每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。
时空限制:
Time limit 6000 ms
Memory limit 1048576 kB
思路:
对于每条指令,设置一个结构体,来存储这条指令的各个信息:类型、操作的文件名s(若有)、以及一个容器用来记录这条操作涉及的目录节点。
对于每个节点,设置一个结构体,来存储这个节点的各个信息:当前节点的名字,父节点,子节点的map映射,以该节点为根的子树的大小。以及各种封装的函数。
对于每组数据,新建一个根节点now,然后根据输入的每条指令修改now节点的位置。
由于具有undo操作,需要记录每条成功执行的指令,开设容器cmdlist来存储执行成功的指令。因此在undo时,每次从容器尾部弹出一个命令,对该命令执行撤销操作。
对于TREE指令,要进行前序和后序遍历,但是在未修改的情况下如果多次出现TREE操作,输出的内容是一样的,但却进行了多次的遍历,会导致超时,因此用容器ten来记录符合要求的节点,如果没有修改,则直接输出。如果修改了,则更新ten后再输出。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
char com[20],sec[20];
struct documents
{
bool flag;
string name;
int child_size;
documents* parent;
vector<string> *ten;
map<string,documents*>child;
documents(string name,documents* parent)
{
this->name=name;
this->parent=parent;
this->child_size=1;
this->ten=new vector<string>;
}
public:
documents* get_child(string name)
{
auto tmp=child.find(name);
if(tmp==child.end())
return nullptr;
return tmp->second;
}
documents* mkdir(string name)
{
if(child.find(name)!=child.end())
return nullptr;
documents* ch=new documents(name,this);
child[name]=ch;
change(+1);
return ch;
}
documents* rm(string name)
{
auto tmp=child.find(name);
if(tmp==child.end())
return nullptr;
change(-1*tmp->second->child_size);
child.erase(tmp);
return tmp->second;
}
documents* cd(string name)
{
if(".."==name)
return this->parent;
return get_child(name);
}
bool add_child(documents* ch)
{
if(child.find(ch->name)!=child.end())
return false;
child[ch->name]=ch;
change(+ch->child_size);
return true;
}
void change(int delta)
{
flag=true;
child_size+=delta;
if(parent!=nullptr)
parent->change(delta);
}
void sz()
{
printf("%d\n",this->child_size);
}
void ls()
{
int sz=child.size();
if(sz==0) printf("EMPTY\n");
else if(sz<=10) for(auto &entry:child) printf("%s\n",entry.first.c_str());
else
{
auto tmp=child.begin();
for(int i=0;i<5;i++,tmp++)
printf("%s\n",tmp->first.c_str());
printf("...\n");
tmp=child.end();
for(int i=0;i<5;i++) tmp--;
for(int i=0;i<5;i++,tmp++)
printf("%s\n",tmp->first.c_str());
}
}
void tree()
{
if(child_size==1) printf("EMPTY\n");
else if(child_size<=10)
{
if(this->flag)
{
ten->clear();
ergodic(ten);
this->flag=false;
}
for(int i=0;i<child_size;i++)
printf("%s\n",ten->at(i).c_str());
}
else
{
if(this->flag)
{
ten->clear();
tree_pre(5,ten);
tree_last(5,ten);
this->flag=false;
}
for(int i=0;i<5;i++)
printf("%s\n",ten->at(i).c_str());
printf("...\n");
for(int i=9;i>=5;i--)
printf("%s\n",ten->at(i).c_str());
}
}
private:
void ergodic(vector<string> *bar)
{
bar->push_back(name);
for(auto &entry:child)
entry.second->ergodic(bar);
}
void tree_pre(int sum,vector<string> *bar)
{
bar->push_back(name);
if(--sum==0) return;
int n=child.size();
auto tmp=child.begin();
while(n--)
{
int st=tmp->second->child_size;
if(st>=sum)
{
tmp->second->tree_pre(sum,bar);
return;
}
else
{
tmp->second->tree_pre(st,bar);
sum-=st;
}
tmp++;
}
}
void tree_last(int sum,vector<string> *bar)
{
int n=child.size();
auto tmp=child.end();
while(n--)
{
tmp--;
int st=tmp->second->child_size;
if(st>=sum)
{
tmp->second->tree_last(sum,bar);
return;
}
else
{
tmp->second->tree_last(st,bar);
sum-=st;
}
}
bar->push_back(name);
}
};
struct command
{
const string cmd_names[7]={"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
int type;
string arg;
documents* tmp_dir;
command(string s)
{
for(int i=0;i<7;i++)
if(cmd_names[i]==s)
{
type=i;
if(i<3)
{
scanf("%s",sec);
arg=sec;
return;
}
}
}
};
int main()
{
int T,n;
cin>>T;
while(T--)
{
documents *now=new documents("root",nullptr);
vector<command*>cmdlist;
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%s",com);
command* cmd=new command(com);
documents* ch;
switch(cmd->type)
{
case 0:
cmd->tmp_dir=now->mkdir(cmd->arg);
if(cmd->tmp_dir==nullptr) printf("ERR\n");
else
{
printf("OK\n");
cmdlist.push_back(cmd);
}
break;
case 1:
cmd->tmp_dir=now->rm(cmd->arg);
if(cmd->tmp_dir==nullptr) printf("ERR\n");
else
{
printf("OK\n");
cmdlist.push_back(cmd);
}
break;
case 2:
{
ch=now->cd(cmd->arg);
if(ch==nullptr) printf("ERR\n");
else
{
printf("OK\n");
cmd->tmp_dir=now;
now=ch;
cmdlist.push_back(cmd);
}
break;
}
case 3:
now->sz();break;
case 4:
now->ls();break;
case 5:
now->tree();break;
case 6:
{
bool success=false;
while(!success&&!cmdlist.empty())
{
cmd=cmdlist.back();
cmdlist.pop_back();
switch(cmd->type)
{
case 0:
success=now->rm(cmd->arg)!=nullptr;break;
case 1:
success=now->add_child(cmd->tmp_dir);break;
case 2:
now=cmd->tmp_dir;success=true;break;
}
}
if(success) printf("OK\n");
else printf("ERR\n");
}
}
}
printf("\n");
}
return 0;
}