A 咕咕东的目录管理器
题目描述
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
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
题目思路
这个题目是一个比较大,并且比较复杂的模拟题,其大致的要求是需要我们维护一个树形结构,然后就是一些对这个树形结构的一些操作。其中比较难的操作主要是TREE和UNDO操作。这就需要我们在执行完操作之后要记录下这些操作的相关信息。
在这个题目中我使用了三个数据结构,Node是数中的节点,包含节点名字name,以它为根的子树的节点个数Size,它的父亲节点fa,标记是否被访问tag;command是命令,dictionary是树,其中包含节点数组nd,当前目录crt,最后一个节点的索引last,记录命令的op数组。
实现方法:
MKDIR s:在当前目录新建一个节点并记录这个命令。
RM s:在当前目录下删除对应节点并记录命令。
CD s:分为两种情况考虑,s是…即返回上一级目录,如果当前目录不是根目录,则将当前目录改为它的父亲目录。否则改变cnt进入对应目录即可。
SZ:返回以当前目录为根的子树的目录个数。
LS:输出当前目录的子目录。
TREE:我们需要注意MKDIR和RM操作非常少,其他操作很多,这样节点数就远远小于TREE数,可能会有重复操作。这样我们就可以使用tag来记录是否被访问。
UNDO:从op中弹出一个命令,然后根据这个命令是MKDIR还是RM进行删除和插入的操作。
代码实现
#include<iostream>
#include<string>
#include<cstring>
#include<vector>
#include<map>
using namespace std;
#define _for(i,a,b) for(int i = (a); i < (b); i++)
#define _rep(i,a,b) for(int i = (a); i <= (b); i++)
struct Node{
string name;
int Size;
int fa;
map<string,int> mp;
vector<string> pre,bck;
int tag;
};
struct command{
string name;
int pos;
command(string n,int i){
name=n;
pos=i;
}
};
class dictionary{
private:
Node nd[5010];
int crt;
int last;
vector<command> op;
public:
dictionary(){
crt=0,last=1;
nd[0].fa=-1;
nd[0].name="root";
nd[0].Size=1;
nd[0].tag=0;
nd[0].pre.clear();
nd[0].bck.clear();
nd[0].mp.clear();
op.clear();
}
void update(int n){
int i=crt;
while(i!=-1){
nd[i].tag=0;
nd[i].Size+=n;
i=nd[i].fa;
}
}
void MKDIR(string s){
if(nd[crt].mp.count(s)){
cout<<"ERR"<<endl;
}
else{
nd[crt].mp[s]=last;
nd[last].name=s;
nd[last].Size=1;
nd[last].fa=crt;
nd[last].mp.clear();
nd[last].pre.clear();
nd[last].bck.clear();
nd[last].tag=0;
update(1);
command cmd("MKDIR",last);
op.push_back(cmd);
last++;
cout<<"OK"<<endl;
}
}
void RM(string s){
if(!nd[crt].mp.count(s))
cout<<"ERR"<<endl;
else{
nd[crt].tag=0;
int i=nd[crt].mp[s];
int sz=nd[i].Size;
nd[crt].mp.erase(s);
update(-sz);
command cmd("RM",i);
op.push_back(cmd);
cout<<"OK"<<endl;
}
}
void CD(string s){
if(s==".."){
if(nd[crt].name=="root")
cout<<"ERR"<<endl;
else{
command cmd("CD",crt);
op.push_back(cmd);
crt=nd[crt].fa;
cout<<"OK"<<endl;
}
}
else{
if(!nd[crt].mp.count(s))
cout<<"ERR"<<endl;
else{
command cmd("CD",crt);
op.push_back(cmd);
int i=nd[crt].mp[s];
crt=i;
cout<<"OK"<<endl;
}
}
}
void SZ(){
cout<<nd[crt].Size<<endl;
}
void LS(){
if(nd[crt].mp.empty())
cout<<"EMPTY"<<endl;
else{
if(nd[crt].mp.size()<=10){
for(map<string,int>::iterator it=nd[crt].mp.begin();it!=nd[crt].mp.end();it++){
cout<<it->first<<endl;
}
}
else{
map<string,int>::iterator it=nd[crt].mp.begin();
_rep(i,1,5)
{
cout<<it->first<<endl;
it++;
}
cout<<"..."<<endl;
it=nd[crt].mp.end();
_rep(i,1,5)
it--;
_rep(i,1,5)
{
cout<<it->first<<endl;
it++;
}
}
}
}
void pretrack(int id,int &cnt,vector<string> &pre){
pre.push_back(nd[id].name);
cnt--;
if(cnt==0) return;
for(map<string,int>::iterator it=nd[id].mp.begin(); it!=nd[id].mp.end(); it++){
pretrack(it->second,cnt,pre);
if(cnt==0) return;
}
}
void bcktrack(int id,int &cnt,vector<string> &bck){
map<string,int>::iterator it=nd[id].mp.end();
while(it!=nd[id].mp.begin())
{
it--;
bcktrack(it->second,cnt,bck);
if(cnt==0) return;
}
bck.push_back(nd[id].name);
cnt--;
}
void pushdown(int id){
nd[id].pre.clear();
nd[id].bck.clear();
if(nd[id].Size<=10){
int sze=nd[id].Size;
pretrack(id,sze,nd[id].pre);
}
else{
int cnt=5;
pretrack(id,cnt,nd[id].pre);
cnt=5;
bcktrack(id,cnt,nd[id].bck);
}
nd[id].tag=1;
}
void TREE(){
if(!nd[crt].tag)
pushdown(crt);
if(nd[crt].Size==1)
cout<<"EMPTY"<<endl;
else {
if(nd[crt].Size<=10)
{
for(int i=0;i<nd[crt].pre.size();i++)
cout<<nd[crt].pre[i]<<endl;
}
else
{
_for(i,0,5)
cout<<nd[crt].pre[i]<<endl;
cout<<"..."<<endl;
for(int i=4;i>=0;i--)
cout<<nd[crt].bck[i]<<endl;
}
}
}
void UNDO(){
if(op.empty())
cout<<"ERR"<<endl;
else{
command cmd=op[op.size()-1];
op.pop_back();
if(cmd.name=="MKDIR")
{
int i=cmd.pos;
int sz=nd[i].Size;
nd[crt].mp.erase(nd[i].name);
update(-sz);
}
else if(cmd.name=="RM")
{
int i=cmd.pos;
int sz=nd[i].Size;
nd[crt].mp[nd[i].name]=i;
int j=crt;
while(j!=-1){
nd[j].tag=0;
nd[j].Size+=sz;;
j=nd[j].fa;
}
}
else
crt=cmd.pos;
cout<<"OK"<<endl;
}
}
};
int main(){
int T;
cin>>T;
_for(i,0,T)
{
int Q;
cin>>Q;
dictionary dic;
_for(j,0,Q)
{
string cmd;
cin>>cmd;
if(cmd=="MKDIR")
{
string s;
cin>>s;
dic.MKDIR(s);
}
else if(cmd=="RM")
{
string s;
cin>>s;
dic.RM(s);
}
else if(cmd=="CD")
{
string s;
cin>>s;
dic.CD(s);
}
else if(cmd=="SZ")
dic.SZ();
else if(cmd=="LS")
dic.LS();
else if(cmd=="TREE")
dic.TREE();
else if(cmd=="UNDO")
dic.UNDO();
}
}
return 0;
}