超级模拟
本来还准备使用更多的面向对象手法的(继承之类),只不过苦于c++的继承掌握不精,且在此题中没有太大的用处,遂放弃
其中book记录了所有的文件的路径和大小方便替换文件时查询大小(不包含文件夹)
用全局函数getNext() 函数分析文件路径
在Dir类中有成员set<Dir> DocS(放文件),和set<PDir>PDirS放指向子文件夹的指针(STL真是好用)
使用PDir类是为了规避set 中的元素不能修改的问题
所有的操作使用递归访问
放代码(超长)
第一次写题解 😎
// 202012-3_带配额的文件系统
// http://118.190.20.162/view.page?gpid=T121
#include<iostream>
#include<string>
#include<set>
using namespace std;
class Doc;
class Dir;
typedef pair<string, bool> PSB;//next dir,reached
typedef long long LL;
set<Doc> book;
PSB getNext(string& path)//在修改path的同时,若p.second==true则返回最后的文件名(文件夹名),若为false则返回最左侧的文件夹名
{
if (path == "/" || path == "")
return make_pair("", true);
//root
int pos = path.find_first_of('/', 1);
string ret;
if (pos == string::npos)// "/A"
{
ret = path.substr(1);
path = "";
return make_pair(ret, true);
}
else// "/A/B"
{
ret = path.substr(1, pos - 1);
path = path.substr(pos);
return make_pair(ret, false);
}
}
class Doc//document
{
public:
LL size;
string add="";//address (for maintainance of book)
string name;
Doc(string newName, LL ns = 0) : name(newName), size(ns) { this->add = ""; }
Doc(string newName, LL ns, string add) :Doc(newName, ns) { this->add = add; }
};
inline bool operator<(const Doc& a,const Doc& b)
{
return a.name < b.name;
}
struct PDir
{
Dir* ptr;
string name;
PDir(string nn = "", Dir* np = nullptr) :name(nn), ptr(np) {}
};
inline bool operator<(const PDir&a,const PDir& b)
{
return a.name < b.name;
}
class Dir//directory
{
public:
LL ld = 0;//目录配额(孩子)
LL lr = 0;//后代配额
LL nowd = 0;//目录下(不含子目录)的文件大小
LL nowr=0;//目录下所有文件(包含子目录)的大小
set<Doc> docS;// doc set
set<PDir> PDirS;// PDir set
bool createDoc(const string& fullPath, string path,const LL &size)
{
if (lr != 0 && nowr + size > lr)
return false;
PSB p = getNext(path);//curr name, reached?
if (p.second)//如果已经在指定目录下,就在该目录下分配
{
if ((ld != 0 && nowd + size > ld) || PDirS.find(PDir(p.first)) != PDirS.end())//且超出限额 或 存在同名文件夹
return false;
nowd += size;
book.emplace(fullPath, size);
docS.emplace(p.first, size, fullPath);
}
else//如果尚未达到
{
if (docS.find(p.first) != docS.end())//要创建文件夹时出现了同名文件
return false;
set<PDir>::iterator it = PDirS.find(PDir(p.first));
bool newlyCreate = false;
if (it == PDirS.end())
{
newlyCreate = true;
it = PDirS.emplace(p.first, new Dir()).first;
}
if (it->ptr->createDoc(fullPath, path, size) == false)
{
if (newlyCreate)
PDirS.erase(it);
return false;
}
}
nowr += size;
return true;
}
bool setLimit(string path, LL ld, LL lr)//设置限额
{
PSB p = getNext(path);
if (p.first=="")//setQ的地址的最后一个是文件夹,所以将终止条件由p.second==true 改为 p.first==""
{
if ((lr != 0 && nowr > lr) || (ld != 0 && nowd > ld))
return false;
this->ld = ld;
this->lr = lr;
}
else
{
set<PDir>::iterator it = PDirS.find(p.first);
if (it == PDirS.end() || it->ptr->setLimit(path, ld, lr) == false)
return false;
}
return true;
}
bool replaceDoc(const string &fullPath,string path, const LL& sizeCh)
{
PSB p=getNext(path);
if (lr != 0 && nowr + sizeCh > lr)
return false;
if (p.second)//在当前目录下更改文件
{
if (ld != 0 && nowd + sizeCh > ld)
return false;
nowd += sizeCh;
set<Doc>::iterator it = (book.find(fullPath));
Doc tmp = *it;
book.erase(*it);
book.emplace(fullPath, tmp.size + sizeCh);
it = docS.find(p.first);
tmp = *it;
docS.erase(it);
docS.emplace(p.first, tmp.size + sizeCh, fullPath);
}
else if (PDirS.find(PDir(p.first))->ptr->replaceDoc(fullPath, path, sizeCh) == false)//在子目录的添加中失败了
return false;
nowr += sizeCh;
return true;
}
LL delFile(string path)//delete
{
PSB p = getNext(path);
if (p.second)//要删除的文件(夹)就在当前文件夹下
{
set<Doc>::iterator di = docS.find(p.first);
if (di != docS.end())//寻找同名文档
{
LL ret = di->size;
book.erase(di->add);
docS.erase(di);
nowd -= ret;
nowr -= ret;
return ret;
}
else//寻找同名文件夹
{
set<PDir>::iterator pi = PDirS.find(p.first);
if (pi == PDirS.end())
return 0;//not found
LL ret = pi->ptr->nowr;
nowr -= ret;
delete pi->ptr;
PDirS.erase(pi);
return ret;
}
}
else
{
set<PDir>::iterator pi = PDirS.find(p.first);
if (pi == PDirS.end())
return 0;
LL toDel = pi->ptr->delFile(path);
nowr -= toDel;
return toDel;
}
}
~Dir()
{
for (Doc i : docS)
book.erase(i.add);
for (PDir i : PDirS)
if (i.ptr!=nullptr)
delete i.ptr;
}
}root;
inline void outputRes(bool f)//output result
{
if (f) cout << "Y" << endl;
else cout << "N" << endl;
}
int main()
{
int n;
cin >> n;
while (n--)
{
char cmd;
string add;
cin >> cmd >> add;
if (cmd == 'C')
{
LL size;
cin >> size;
set<Doc>::iterator it = book.find(add);
if (it != book.end())
outputRes(root.replaceDoc(add, add, size - it->size));
else
outputRes(root.createDoc(add, add, size));
}
else if (cmd == 'R')
{
root.delFile(add);
cout << "Y" << endl;
}
else//Q
{
LL ld, lr;
cin >> ld >> lr;
outputRes(root.setLimit(add, ld, lr));
}
}
return 0;
}
/*
6
C /A/a1 100
C /A/a2 100
C /A/B/b1 200
C /A/B/b2 200
C /A/B/b2 300
R /A
*/