【A - 咕咕东的目录管理器】

题意:

初始时,硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
在命令行下执行以下表格中描述的命令:
命令 类型 实现 说明
MKDIR s 操作 在当前目录下创建一个子目录 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 个。若目录结构如上图,当前目录为 “root” 执行结果如下,
UNDO 特殊 撤销操作 撤销最近一个 “成功执行” 的操作(即MKDIR或RM或CD)的影响,撤销成功输出 “OK” 失败或者没有操作用于撤销则输出 “ERR”

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

思路:

数据结构有两个:Directory和command。Directory存储结点的结构,command存储命令的结构。
MKDIR:新建子目录,先检查是否已经存在,因为有可能撤销,所以在新建子目录的时候记录新建的子目录、命令、当前节点等。
RM:去掉连着之间的连接,但不会删除某个节点。记录有关命令的信息。
CD:进入子目录,记录有关命令的信息,便于后续反向行走。
SZ:直接输出当前节点记录的以当前节点为根的子树的大小。
LS:输出节点记录的pre和bck。
UNDO:从记录的命令中取出最新的一条,不同的命令有对应的不同的撤销操作。

代码:

#include<iostream>
#include <cstdio>
#include<string>
#include<map>
#include<vector>
using namespace std;
char tmps[20];
struct Directory
{
	string name;//当前目录的名字
	map<string, Directory*> children;
	Directory* parent;
	int subtreeSize;
	bool updated;//记录当前节点的子孙有无变动,无变动则十个后代无需更新
	vector<string>* tenDescendants;//保存当前节点的“十个后代”
	Directory(string name, Directory* parent)
	{
		this->name = name;
		this->parent = parent;
		this->subtreeSize = 1;
		updated = false;
		children.clear();
		this->tenDescendants = new vector<string>;
	}
public:
	Directory* getChild(const string& name)//取子目录返回,不存在则返回空指针
	{
		auto it = children.find(name);
		if (it == children.end())
			return nullptr;
		return it->second;
	}
	Directory* mkdir(const string& name)//创建子目录返回,创建失败则返回空指针
	{
		if (children.find(name) != children.end())
			return nullptr;
		Directory* ch = new Directory(name, this);
		children[name] = ch;
		maintain(+1);
		return ch;
	}
	Directory* rm(const string& name)//删除子目录返回,删除失败则返回空指针
	{
		auto it = children.find(name);
		if (it == children.end()) return nullptr;
		maintain(-1 * (it->second->subtreeSize));
		children.erase(it);
		return it->second;
	}
	Directory* cd(const string& name)
	{
		if (name == "..")
			return this->parent;
		return getChild(name);
	}
	bool addChild(Directory* ch)
	{
		if (children.find(ch->name) != children.end())
			return false;
		children[ch->name] = ch;
		maintain(ch->subtreeSize);
		return true;
	}
	void maintain(int delta)
	{
		updated = true;
		subtreeSize += delta;
		if (parent != nullptr)
			parent->maintain(delta);
	}
	void sz()
	{
		printf("%d\n", this->subtreeSize);
	}
	void ls()
	{
		int sz = children.size();
		if (sz == 0)
			printf("EMPTY\n");
		else if (sz <= 10)
			for (auto& entry : children)
				printf("%s\n", entry.first.c_str());
		else
		{
			auto it = children.begin();
			for (int i = 0; i < 5; i++, it++)
				printf("%s\n", it->first.c_str());
			printf("...\n");
			it = children.end();
			for (int i = 0; i < 5; i++)
				it--;
			for (int i = 0; i < 5; i++, it++)
				printf("%s\n", it->first.c_str());
		}
	}
	void tree()
	{
		if (subtreeSize == 1)
			printf("EMPTY\n");
		else if (subtreeSize <= 10)
		{
			if (this->updated)
			{
				tenDescendants->clear();
				treeAll(tenDescendants);
				this->updated = false;
			}
			for (int i = 0; i < subtreeSize; i++)
				printf("%s\n", tenDescendants->at(i).c_str());
		}
		else
		{
			if (this->updated)
			{
				tenDescendants->clear();
				treeFirstSome(5, tenDescendants);
				treeLastSome(5, tenDescendants);
				this->updated = false;
			}
			for (int i = 0; i < 5; i++)
				printf("%s\n", tenDescendants->at(i).c_str());
			printf("...\n");
			for (int i = 9; i >= 5; i--)
				printf("%s\n", tenDescendants->at(i).c_str());
		}
	}
private:
	void treeAll(vector<string>* bar)//全部后代加入桶
	{
		bar->push_back(name);
		for (auto& entry : children)
			entry.second->treeAll(bar);
	}
	void treeFirstSome(int num, vector<string>* bar)
	{
		bar->push_back(name);
		if (--num == 0)
			return;
		int n = children.size();
		auto it = children.begin();
		while (n--)
		{
			int sts = it->second->subtreeSize;
			if (sts >= num)
			{
				it->second->treeFirstSome(num, bar);
				return;
			}
			else
			{
				it->second->treeFirstSome(sts, bar);
				num -= sts;
			}
			it++;
		}
	}
	void treeLastSome(int num, vector<string>* bar)
	{
		int n = children.size();
		auto it = children.end();
		while (n--)
		{
			it--;
			int sts = it->second->subtreeSize;
			if (sts >= num)
			{
				it->second->treeLastSome(num, bar);
				return;
			}
			else
			{
				it->second->treeLastSome(sts, bar);
				num -= sts;
			}
		}
		bar->push_back(name);
	}
};
struct Command
{
	const string CMDNAMES[7] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
	int type;//命令的类型
	string arg;//命令的参数
	Directory* tmpDir;//记录刚刚操作涉及的目录节点
	Command(const string& s)
	{
		tmpDir = nullptr;
		for (int i = 0; i < 7; i++)
		{
			if (CMDNAMES[i] == s)
			{
				type = i;
				if (i < 3)
				{
					scanf("%s", tmps);
					arg = tmps;
					return;
				}

			}
		}
	}
};
void solve()
{
	int Q = 0;
	scanf("%d", &Q);
	Directory* now = new Directory("root", nullptr);
	vector<Command*> cmdList;//新增加的数组存成功执行的命令以备"UNDO"
	while (Q--)
	{
		scanf("%s", tmps);
		Command* cmd = new Command(tmps);
		switch (cmd->type)
		{
		case 0: case 1:
		{
			cmd->tmpDir = (cmd->type == 0) ? now->mkdir(cmd->arg) : now->rm(cmd->arg);
			if (cmd->tmpDir == nullptr)
				printf("ERR\n");
			else
			{
				printf("OK\n");
				cmdList.push_back(cmd);
			}
			break;
		}
		case 2:
		{
			Directory* ch = now->cd(cmd->arg);
			if (ch == nullptr)
				printf("ERR\n");
			else
			{
				printf("OK\n");
				cmd->tmpDir = 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;//UNDO执行成功与否
			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->addChild(cmd->tmpDir);
					break;
				case 2:
					now = cmd->tmpDir;
					success = true;
					break;
				}
			}
			printf(success ? "OK\n" : "ERR\n");
		}
		}
	}
}
int main()
{
	int T;
	scanf("%d", &T);
	for (int i = 1; i <= T; i++)
	{
		solve();
		if (i != T) 
			printf("\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值