题目
样例输入
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
样例输出
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
思路
咋一看这题有点懵,用什么数据结构存储?树?
因为在每个子目录下,使用字典序排序,因此可以使用map记录子目录。map的first存子目录的名字,second存目录类型的指针。
目录类型主要包括姓名、父亲目录的指针和目录的map。为方便操作还有treeSize,flag等元素。
同时,声明数据类型Command,对输入的指令进行操作(包括分析指令,存储参数等)。
目录中还包含了几乎涵盖题目要求的所有操作。其中,前三个操作并不是直接输出,而转移到了处理函数solve()中解决。因为这三个操作可能需要UNDO,因此不仅需要输出,还要返回UNDO必要的参数。
因为UNDO操作的需求,在删除子目录时只是将子目录从当前目录的map中摘除,而不将子目录中的内容清空。
另外,UNDO操作因为需要指令的信息,所以无法在Directory中声明操作,而直接在solve()中处理。
本题,最最关键的问题是时间限制和数据范围。命令总数1e5,也就是说TREE操作的数目极限情况下差不多要到1e5次,多组数据最多20组,显然如果每一次TREE操作都进行遍历的话会超时。
因此,采用懒更新的方法,在每次进行插入或删除操作时标记更新,然后在进行TREE操作时将答案存储。如果下次进行TREE操作没有更新,无需重新遍历,直接输出即可。
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include<map>
#include<vector>
#include<stack>
using namespace std;
string order;//辅助输入的字符串数组,指令名称
struct Directory//字典
{
string name;//当前目录的名字
map<string, Directory*> children;//子目录
Directory* parent; //方便返回上一层目录
int treeSize;//子树大小
bool flag;//标记是否被更新过
vector<string>* tenChild;
Directory(string name, Directory* parent)
{
this->name = name;
this->parent = parent;
this->treeSize = 1;
tenChild = new vector<string>;
flag = true;
}
public:
Directory* mkdir(string name);
Directory* rm(string name);
Directory* cd(string name);
void update(int num);
bool addChild(Directory *child);
void sz();
void ls();
void tree();
protected:
void all(vector<string>* bar);
void pre(int &num, vector<string>* bar);
void post(int &num, vector<string>* bar);
};
struct Command
{
const string cmdName[7]{ "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
int type;//命令的类型
string arg;//命令的参数
Directory* last;
Command(string s)
{
for (int i = 0; i < 7; i++)
{
if (cmdName[i] == s)
{
type = i;
if (i < 3)
{
cin >> order;
arg = order;
}
}
}
}
};
void Directory::update(int num)
{//更新每个字典的信息
flag = true;
treeSize += num;
if (parent != nullptr)
parent->update(num);
}
Directory* Directory::mkdir(string name)
{//创建子目录成功,返回子目录指针
if (children.find(name) != children.end())//已经存在
return nullptr;
Directory *child = new Directory(name, this);
children[name] = child;
update(1);
return child;
}
Directory* Directory::rm(string name)
{//删除成功,返回子目录指针
map<string, Directory*>::iterator it = children.find(name);
if (it == children.end())
return nullptr;
Directory* com = it->second;
update(-1 * it->second->treeSize);
children.erase(it);
return com;
}
bool Directory::addChild(Directory* child)//增加子目录
{
if (children.find(child->name) != children.end())//已经存在
return false;
children[child->name] = child;
update(child->treeSize);
return true;
}
void Directory::sz()
{
cout << this->treeSize << endl;
}
void Directory::ls()
{
int size = children.size();
if (size == 0) cout << "EMPTY" << endl;
else if (size <= 10)
for (map<string, Directory*>::iterator it = children.begin();
it != children.end(); it++)
cout << it->first << endl;
else
{
map<string, Directory*>::iterator it = children.begin();
for (int i = 0; i < 5; i++, it++)
cout << it->first << endl;
cout << "..." << endl;
it = children.end();
for (int i = 0; i < 5; i++) it--;
for (int i = 0; i < 5; i++, it++) cout << it->first << endl;
}
}
Directory* Directory::cd(string name)
{
if (name == "..")
return parent;
map<string, Directory*>::iterator it = children.find(name);
if (it == children.end())
return nullptr;
else return it->second;
}
void Directory::tree()
{
int size = this->treeSize;
if (size == 1) cout << "EMPTY" << endl;
else if (size <= 10)
{
if (flag)
{
tenChild->clear();
all(tenChild);
flag = false;
}
for (int i = 0; i < size; i++) cout << tenChild->at(i) << endl;
}
else
{
if (flag)
{
tenChild->clear();
int num = 5;
pre(num, tenChild);
num = 5;
post(num, tenChild);
flag = false;
}
for (int i = 0; i < 5; i++)
cout << tenChild->at(i) << endl;
cout << "..." << endl;
for (int i = 9; i >= 5; i--)
cout << tenChild->at(i) << endl;
}
}
void Directory::all(vector<string>* bar)
{
bar->push_back(this->name);
for (map<string, Directory*>::iterator it = children.begin();
it != children.end(); it++)
it->second->all(bar);
}
void Directory::pre(int &num, vector<string>* bar)
{
if (num <= 0) return;
bar->push_back(this->name);
int size = this->treeSize;
map<string, Directory*>::iterator it = children.begin();
int sz = children.size();
for (int i = 0; i < sz; i++, it++)
it->second->pre(--num, bar);
}
void Directory::post(int &num, vector<string>* bar)
{
int size = this->treeSize;
map<string, Directory*>::iterator it = children.end();
if (children.size() != 0)
{
it--;
int sz = children.size();
for (int i = 0; i < sz; i++, it--)
it->second->post(num, bar);
}
if (num <= 0) return;
bar->push_back(this->name);
num--;
}
void solve()
{
int Q;
cin >> Q;
Directory *now = new Directory("root", nullptr);
stack<Command*> done; //存储成功执行的命令
while (Q--)
{
cin >> order;
Command *cmd = new Command(order);
switch (cmd->type)
{
case 0://mkdir创建子目录
{
cmd->last = now->mkdir(cmd->arg);
if (cmd->last == nullptr) cout << "ERR" << endl;
else
{
cout << "OK" << endl;
done.push(cmd);
}
break;
}
case 1://rm 删除子目录
{
//cout << "in" << endl;
cmd->last = now->rm(cmd->arg);
if (cmd->last == nullptr) cout << "ERR" << endl;
else
{
cout << "OK" << endl;
done.push(cmd);
}
break;
}
case 2://cd 进入目录
{
Directory* re = now->cd(cmd->arg);
if (re == nullptr) cout << "ERR" << endl;
else
{
cout << "OK" << endl;
cmd->last = now;
now = re;
done.push(cmd);
}
break;
}
case 3:
{
now->sz();
break;
}
case 4:
{
now->ls();
break;
}
case 5:
{
now->tree();
break;
}
case 6:
{
bool is = false;
while (!is && !done.empty())
{
cmd = done.top();
done.pop();
if (cmd->type == 0)
{
if (now->rm(cmd->arg) != nullptr)
is = true;
break;
}
if (cmd->type == 1)
{
is = now->addChild(cmd->last);
break;
}
else
{
now = cmd->last;
is = true;
break;
}
}
if (!is) cout << "ERR" << endl;
else cout << "OK" << endl;
break;
}
}
}
}
int main()
{
int T;
cin >> T;
while (T--) solve();
system("Pause");
return 0;
}