CCF CSP 202012-3 带配额的文件系统题解

超级模拟
本来还准备使用更多的面向对象手法的(继承之类),只不过苦于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

*/
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值