解题思路:
这道题的大体框架就在于两个结构体,一个command(命令),一个directory(目录),一条命令不单有命令形式,还有命令参数,比如“MKDIR s”等等,所以还需要进行参数的分离,同类信息需要聚集,所以将它封装成command结构体更好处理。将七种命令封装成常量数组cmdnames,command结构体还包括type表示命令种类,arg存储参数(可能存在)以及记录刚刚操作设计的目录节点tempdir。directory结构体用来存储目录,因为题目要求需要能根据子目录名字访问子目录,所以孩子节点children采用映射map<string, directory*>来进行存储。为了降低sz操作的复杂度,我们增加变量int size_of_subtree用来记录以当前节点为根的子树的节点数目,这样sz操作直接返回size_of_subtree的值即可。其他操作都有相应的函数来直接实现,难度都不大,具体可见上课时的课件,着重分析一下tree的操作,TREE 的命令条数最多约为 1e5,此时整个树最多 5000 个节点,复杂度约为20x1e5x5000,很可能会 TLE。为了降低复杂度,本题中最重要的一步就在于tree操作中的缓存(懒更新),节点数是远少于 TREE 操作数的,很有可能还有重复询问,对于目录相同期间问过的相同问题,理应只有一次是计算过程,增加bool类型变量updated用来记录当前节点的子树有无变动,没有变动时可以直接输出des中的内容(最多只记录10个后代),有变动才会对des进行更新,所以当目录没有发生变化时,不需要重新生成前序序列,直接输出des中记录好的没有变动的后代信息即可,降低时间代价。还有重要的一步是undo操作,用bool变量flag记录undo是否成功,用command*类型的动态数组存储成功执行的命令,这样当需要撤销时只需要从这个动态数组中依次取出成功执行的命令进行撤销操作即可。
参考代码:
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
char temp[25];
struct directory;
struct command{
//命令
const string cmdnames[7]={
"MKDIR","RM","CD","SZ","LS","TREE","UNDO"};
int type;
string arg;
directory* tempdir;//刚刚操作设计的目录节点
command(string str){
for (int i=0; i<7; i++) {
if(cmdnames[i]==str){
type=i;
if(i<3){
scanf("%s",temp);arg=temp;}
}
}
}
};
struct directory{
//目录
string name;bool updated;//记录子树有无更新
map<string, directory*> children;//需要能根据子目录名字访问子目录
directory* parent;
int size_of_subtree;
vector<string> mydes;//当前节点的十个后代
void sz(){
cout<<this->size_of_subtree<<endl;
}
void fix(int d){
//向上维护子树大小
this->updated=true;
size_of_subtree=size_of_subtree+d;
if(parent==nullptr)return;
else{
parent->fix(d);
}
}
directory(string name,directory* parent){
this->name=name;
this->parent=parent;
this->size_of_subtree=1;
}
directory*getchild(string name){
auto tmp<