CSP 202012-3: 带配额的文件系统。100 分AC, 虽然是事后(皮)

CSP 202012-3: 带配额的文件系统。100 分 AC,虽然是事后(皮)

#include<iostream>
#include<string>
#include<vector>
#include<map> 

using namespace std;

// 不进行提前记录,只能通过 70% 的测试用例,剩下的会超时(因为数据规模很大)
typedef struct treeNode {
	bool isFile; // true then file, false then dirctory
	long long LD, LR; // child limit  &  after children limit. Valid only isFile is false
	long long lr; // Valid only is a dir: 提前地、动态地、实时地记录后代配额,这样就不用进行庞大的递归计算了
	long long size; // Valid only is File is true
	map<string, struct treeNode*> children; // children's name: tree
} TreeNode, * Tree;

int main() {
	int n;
	long long calculateD(Tree);
	long long calculateR(Tree);
	bool create(Tree, string, long long);
	void remove(Tree, string);
	bool setQ(Tree, string, long long, long long);
	cin >> n;
	char* result = new char[n]();
	// initialize tree
	Tree tree = new TreeNode();
	// initialization done
	char command;
	string filePath; // directory's path or file's path
	string dirPath; // must be directory's path
	long long size;
	long long ld, lr;
	for (int time = 0; time < n; time++) {
		cin >> command;
		char success = 'Y';
		switch (command) {
		case 'C':
			cin >> filePath >> size;
			if (!create(tree, filePath, size))
				success = 'N';
			break;
		case 'R':
			cin >> filePath;
			remove(tree, filePath);
			break;
		case 'Q':
			cin >> dirPath >> ld >> lr;
			if (!setQ(tree, dirPath, ld, lr))
				success = 'N';
		}

		result[time] = success; // or 'N'
	}

	for (int i = 0; i < n; i++)
		cout << result[i] << endl;

	return 0;
}

vector<string> split(string filePath) { // create a wheel by myself, split a string to strs
	vector<string> vs;
	int start, end;
	int len = filePath.size();
	string s;
	start = 1;
	for (end = 1; end < len; end++) {
		// mainly use string object's assign(src_str, start_i, length) function
		if (filePath[end] == '/') {
			s.assign(filePath, start, end - start);
			vs.push_back(s);
			start = end + 1;
		}
	}
	if (len != 1) {
		s.assign(filePath, start, start - end);
		vs.push_back(s);
	}

	return vs;
}

void remove(Tree T, string filePath) {
	Tree tree = T;
	vector<string> vs = split(filePath);
	int len = vs.size();
	map<string, Tree>::iterator iter;
	int i;
	for (i = 0; i < len - 1; i++) {
		map<string, Tree>& children = tree->children;
		iter = children.find(vs[i]);
		if (iter == children.end())
			return;
		else
			tree = iter->second;
	}
	if (tree->isFile) return;
	map<string, Tree>& children = tree->children;
	iter = children.find(vs[i]);
	if (iter == children.end())
		return;
	

	// 现在确定指令正确,必然要删文件,tree 指向了待删结点的父结点。
	// for function create version 3.0, 删除目录之前,要先使用被删结点的信息 lr or size,
	// 以更新将要被删的文件路径上所有的目录的 lr
	long long minus;
	if (iter->second->isFile) minus = iter->second->size;
	else minus = iter->second->lr; 

	T->lr -= minus;
	for (i = 0; i < len - 1; i++) {
		map<string, Tree>& children = T->children;
		T = children[vs[i]];
		T->lr -= minus;
	}

	// 更新完成,可以删除了
	map<string, Tree>& c = tree->children;
	c.erase(vs[len-1]);
}

long long calculateD(Tree tree) {
	map<string, Tree>& children = tree->children;
	map<string, Tree>::iterator iter = children.begin();
	long long total = 0;
	for (; iter != children.end(); iter++)
		if (iter->second->isFile) total += iter->second->size;
	return total;
}

long long calculateR(Tree tree) {
	long long total = 0;
	map<string, Tree>& children = tree->children;
	map<string, Tree>::iterator iter = children.begin();
	for (; iter != children.end(); iter++) {
		if (iter->second->isFile) total += iter->second->size;
		else total += calculateR((Tree)iter->second);
	}
	return total;
}

// previously record every directory's lr, which is the sum of all the files' sizes,
// avoiding recursively calculating.
bool create(Tree T, string filePath, long long size) {
	Tree tree = T;

	/* Step 1: 走到已存在的最后一个目录 */
	vector<string> vs = split(filePath);
	int len = vs.size();
	int i;
	map<string, Tree>::iterator iter;
	for (i = 0; i < len - 1; i++) {
		map<string, Tree>& children = tree->children;
		iter = children.find(vs[i]);
		if (iter == children.end())  // 不存在这个目录,就 break 出来创建后面所有的目录
			break;
		tree = iter->second;
		if (tree->isFile) return false; // 有重名普通文件,执行失败
		// else it is a directory
	}

	/* Step 2: 检测前面存在的目录是否超出 LR 配额 */
	long long delta;
	if (i < len - 1) { // 提前跳出 for,表示目录不存在,要进行创建
		// 此时,delta 等于 size
		delta = size;
	}
	else { // i == len - 1, 路径上所有目录都存在,看是否有此文件
		map<string, Tree>& children = tree->children;
		iter = children.find(vs[i]);
		if (iter != children.end()) { // 有此文件,看是否是普通文件
			// delta 等于 new size - old size
			if (iter->second->isFile)  // 是普通文件,看是否 满足 tree 的 LD
				delta = size - iter->second->size;
			else return false; // 是个重名目录,执行失败
		}
		else  // 无此文件,要进行创建,delta 等于 size
			delta = size;

		if (tree->LD > 0 && calculateD(tree) + delta > tree->LD)
			return false;
	}
	// 至此,可以使用 delta 来检测路径上已存在目录的配额是否超出了
	int j;
	tree = T;
	if (tree->LR > 0 && tree->lr + delta > tree->LR)
		return false;
	for (j = 0; j < i; j++) { // i 是第一个没有找到的目录,or 路径终点的普通文件
		map<string, Tree>& children = tree->children;
		tree = children[vs[j]];
		if (tree->LR > 0 && tree->lr + delta > tree->LR)
			return false;
	}
	// 至此,所有条件都满足,能执行成功
	// 可以进行路径上未存在的目录和文件的创建了

	/* Step 3: 创建后面所有不存在的目录 */ 
	for (; i < len - 1; i++) {
		map<string, Tree>& children = tree->children;
		children[vs[i]] = new TreeNode();
		tree = children[vs[i]];
	}
	// 下面这种写法,可以统一 3 种情况:目录和文件都存在、目录存在文件不存在、目录和文件都不存在
	map<string, Tree>& children = tree->children;
	iter = children.find(vs[i]);
	
	if (iter == children.end()) { // 新建文件
		children[vs[i]] = new TreeNode();
		tree = children[vs[i]];
		tree->isFile = true;
		tree->size = size;
	}
	else { // 已存在, 则修改文件
		tree = iter->second;
		tree->size = size;
	}

	/* Step 4: 因为成功创建了文件,所以路径上所有目录的 lr 都加上一个 delta */
	T->lr += delta;
	for (i = 0; i < len - 1; i++) {
		map<string, Tree>& children = T->children;
		T = children[vs[i]];
		T -> lr += delta;
	}

	return true;
}

bool setQ(Tree tree, string dirPath, long long ld, long long lr) {
	vector<string> vs = split(dirPath);
	int len = vs.size();
	map<string, Tree>::iterator iter;
	for (int i = 0; i < len; i++) {
		map<string, Tree>& children = tree->children;
		iter = children.find(vs[i]);
		if (iter == children.end()) // not exists
			return false;
		tree = iter->second;
	}
	if (tree->isFile) return false; // not directory

	if (ld > 0 && calculateD(tree) > ld
		|| lr > 0 && tree->lr > lr)
		return false;
	// else
	tree->LD = ld;
	tree->LR = lr;

	return true;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值