SDU程序设计思维Week9
A-咕咕东的目录管理器
Description
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
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
Idea
题意:通过七种命令维护、查询一个目录管理器,我们对每种操作分而治之
-
初始化
Command类对应一条命令,包含命令的类型,对于三种操作要存储s
Directory类对应目录中的节点,每个节点存储了自己的后代,父亲节点、大小等
初始化根目录节点root
now代表当前目录,cnt代表整个目录的节点数 -
MKDIR s-创建子目录
创建前检查当前目录是否存在重名,存在重名输出ERR
无重名,则创建节点,节点的父亲是当前目录,并把该节点放入当前目录的后代中
逐层向上更新目录的大小+1(具体在SZ中说明)
存储本次操作(具体在UNDO中说明) -
RM s-删除子目录
在当前目录搜索要删除的子目录,如果不存在输出ERR
找到对应节点后,从当前目录的后代中删除它
逐层向上更新目录的大小,都减去删除的子目录的大小(具体在SZ中说明)
存储本次操作(具体在UNDO中说明) -
CD s-进入子目录
s="…"时代表返回当前目录的上一层,如果不存在上一层则输出ERR
其他情况中首先搜索要切换到的子目录,如果不存在该子目录则输出ERR,存在则更新当前目录
对于不输出ERR的所有情况,存储本次操作 -
SZ-输出当前目录大小
可以看到在上面创建或删除子目录时我们都维护了目录的大小,这方便了SZ查询
在O(1)的复杂度下可以直接查询到当前目录的大小 -
UNDO-撤销
可以看到在上面三种类型为操作的命令中,我们都用vector存储了每次操作。
当没有任何操作可以撤销时,输出ERR
数组中有操作时,拿出最后一次操作,进行对应的反操作
MKDIR s反操作对应RM s,RM s反操作对应MKDIR s,CD s反操作切换回执行前的当前目录即可
在前两种撤销后记得要返回到原来撤销前的当前目录,也要相应更新目录的大小 -
LS-输出当前目录的直接子目录名
当无后代时输出EMPTY
后代数量在1~10时输出所有子目录,大于10时输出前5个和后5个(利用迭代器) -
TREE-输出以当前目录为根的子树
对当前目录下所有节点构造前序序列和后序序列,并标记已构造,对于更新过目录的大小的节点需要重新构造序列(保证最新性)
当子树节点数量(1,10]时输出前序序列(构造时只需要构造前序序列即可),大于10时输出前序序列的前五和后序序列的后五(前序和后序都要构造)
前序序列构造中,按前序逐个对节点的序列进行递归地构造,当子目录数量超过10就只需维护前五个子目录
后序序列构造中,只要使用到后序序列的构造,子目录的数量必然超过10个,只需要维护最后五个子目录(满足五个后记得取数组的逆序),按后序逐个对节点的序列进行递归地构造获得当前目录下的最后五个子目录。 -
实现上述7种命令后,根据命令的类别值执行对应操作即可。
Summary
这题是复杂的模拟题,简而言之,就是分别实现这七种命令。可以先分而治之,独立实现各个命令,好的封装可以理清思路。再寻求各个命令之间的联系以降低某些复杂命令的时间复杂度,例如本题前三种操作中维护了目录的大小、存储了操作为查询目录大小和撤销作好了铺垫。
多组操作,要注意初始化问题!!
Codes
#include <iostream>
#include <cstring>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
using namespace std;
int T,Q;
const string cmd_string[] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
//命令
struct Command {
string name, str;
int type;
void init(string s) {
name = s;
for (int i = 0; i < 7; i++) {
if (s == cmd_string[i]) {
type = i;
if (i < 3)cin >> str;
break;
}
}
}
}cmd;
//目录
struct Directory {
string name;
//存储后代,<名称,编号>
map<string, int> mp;
int parent, sz;
vector<string> pre, bck;
bool tag;
void init(string s, int p) {
tag = 0;
parent = p;
sz = 1;
name = s;
pre.clear();
bck.clear();
mp.clear();
}
}node[100100];
int cnt,now; //节点数,当前节点
vector<pair<string, pair<int, int>>> v; //存储步骤
void update(int x, int num) {
while (x != - 1) {
node[x].tag = 0;
node[x].sz += num;
x = node[x].parent;
}
}
void make_node(string s,int p) {
node[++cnt].init(s, p);
node[p].mp[s] = cnt;
}
//创建
void mkdir() {
if (node[now].mp.count(cmd.str)) {
cout << "ERR" << endl;
return;
}
make_node(cmd.str, now);
v.push_back(make_pair("MKDIR", make_pair(now, cnt)));
update(now, 1);
cout << "OK" << endl;
}
//删除
void rm() {
if (!node[now].mp.count(cmd.str)) {
cout << "ERR" << endl;
return;
}
int u = node[now].mp[cmd.str];
update(now, -node[u].sz);
v.push_back(make_pair("RM", make_pair(now, u)));
node[now].mp.erase(node[u].name);
cout << "OK" << endl;
}
//切换
void cd() {
if (cmd.str == "..") {
if (node[now].parent == -1) {
cout << "ERR" << endl;
return;
}
v.push_back(make_pair("CD", make_pair(now, node[now].parent)));
now = node[now].parent;
cout << "OK" << endl;
return;
}
if (!node[now].mp.count(cmd.str)) {
cout << "ERR" << endl;
return;
}
int u = node[now].mp[cmd.str];
v.push_back(make_pair("CD", make_pair(now, u)));
now = u;
cout << "OK" << endl;
}
//大小
void sz() {
cout << node[now].sz << endl;
}
//撤销
void undo() {
if (v.size() == 0) {
cout << "ERR" << endl;
return;
}
auto t = v[v.size() - 1];
v.pop_back();
cout << "OK" << endl;
int temp = now;
if (t.first == "MKDIR") {
cmd.name = "RM";
now = t.second.first;
cmd.str = node[t.second.second].name;
int u = node[now].mp[cmd.str];
update(now, -node[u].sz);
node[now].mp.erase(node[u].name);
now = temp;
}
else if (t.first == "RM") {
//cmd.name = "MKDIR";
now = t.second.first;
int u = t.second.second;
update(now, node[u].sz);
node[now].mp[node[u].name] = u;
now = temp;
}
else now = t.second.first;
}
//当前目录文件夹
void ls() {
int m = node[now].mp.size();
if (m == 0) {
cout << "EMPTY" << endl;
return;
}
else if (m >= 1 && m <= 10) {
auto u = node[now].mp.begin();
while (u != node[now].mp.end()) {
cout << u->first << endl;
u++;
}
return;
}
else if (m > 10) {
auto u = node[now].mp.begin();
for (int i = 1; i <= 5; i++)
{
cout << u->first << endl;
u++;
}
cout << "..." << endl;
u = node[now].mp.end();
for (int i = 1; i <= 5; i++)u--;
for (int i = 1; i <= 5; i++)
{
cout << u->first << endl;
u++;
}
}
}
//tree
void pushdown(int x);
void pretrack(int x) {
node[x].pre.push_back(node[x].name);
if (node[x].sz == 1)return;
if (node[x].sz <= 10) {
for (auto i : node[x].mp) {
if (!node[i.second].tag)pushdown(i.second);
node[x].pre.insert(node[x].pre.end(), node[i.second].pre.begin(), node[i.second].pre.end());
}
return;
}
int pos = 1;
for (auto i : node[x].mp) {
if (!node[i.second].tag)pushdown(i.second);
for (auto j : node[i.second].pre) {
node[x].pre.push_back(j);
pos++;
if (pos >= 5)break;
}
if (pos >= 5)break;
}
}
void bcktrack(int x) {
auto it = node[x].mp.end();
it--;
int pos = 0;
for (;;it--) {
int u = it->second;
if (!node[u].tag)pushdown(u);
for (int i = node[u].bck.size() - 1; i >= 0; i--) {
node[x].bck.push_back(node[u].bck[i]);
pos++;
if (pos >= 5) {
reverse(node[x].bck.begin(), node[x].bck.end());
break;
}
}
if (pos >= 5)break;
if (it == node[x].mp.begin())break;
}
}
void pushdown(int x) {
//构造pre和back
node[x].pre.clear();
node[x].bck.clear();
pretrack(x);
if (node[x].sz > 10)bcktrack(x);
else node[x].bck = node[x].pre;
node[x].tag = 1;
}
void tree() {
if (!node[now].tag)pushdown(now); //构造pre和back
int m = node[now].sz;
if (m == 1)cout << "EMPTY" << endl;
else if (m > 1 && m <= 10) {
for (int i = 0; i < node[now].pre.size(); i++)
cout << node[now].pre[i] << endl;
}
else {
for (int i = 0; i < 5; i++)
cout << node[now].pre[i] << endl;
cout << "..." << endl;
for (int i = 5; i >=1; i--)
cout << node[now].bck[node[now].bck.size()-i] << endl;
}
}
void init() {
cnt = now = 0;
v.clear();
node[0].init("root", -1);
}
void solve() {
for (int i = 1; i <= Q; ++i) {
string s;
cin >> s;
cmd.init(s);
int x = cmd.type;
if (x == 0)mkdir();
else if (x == 1)rm();
else if (x == 2)cd();
else if (x == 3)sz();
else if (x == 4)ls();
else if (x == 5)tree();
else if (x == 6)undo();
}
}
int main()
{
cin.sync_with_stdio(false);
cin >> T;
while (T--) {
cin >> Q;
init();
solve();
}
}