2020 年 12 月 CCF CSP 21 第三题 带配额的文件系统

http://118.190.20.162/view.page?gpid=T121

提交结果

代码长度 编程语言 得分 时间使用 空间使用
7.515KB CPP11 100 671ms 16.47MB

代码

#include 
#include 
#include 
#include 
#include 
using namespace std;

// #define DEBUG(cmd) cmd;
#define DEBUG(cmd) ;

template <typename T>
void print(const vector<T>& v) {
	for (const auto& e : v) {
		cout << e << " ";
    }
    cout << endl;
}

namespace path {
	void split(vector<string>& result, const string& filepath) {
		assert(result.size() == 0);
		for (int i = 1, j; i < filepath.size(); i = j + 1) {
			for (j = i; j < filepath.size() && filepath[j] != '/'; j++);
			result.push_back(filepath.substr(i, j - i));
		}
	}

	void dirname(vector<string>& result, const vector<string>& filepath) {
		assert(result.size() == 0);
		result.insert(result.begin(), filepath.begin(), filepath.end() - 1);
	}

	void basename(string& result, const vector<string>& filepath) {
		assert(result.size() == 0);
		result = filepath.back();
	}
}

class Directory {
	map<string, Directory*> _directories;
	map<string, int> _files;
	unsigned long long _directSize = 0, _size = 0, _ld = 0, _lr = 0;
	friend void _tree(Directory* root, const string& dirname, const unsigned long long indent);
public:
	bool hasSubDirectory(const string& name) const {
		return _directories.count(name) > 0;
	}

	bool hasFile(const string& name) const {
		return _files.count(name) > 0;
	}

	bool hasDirectFreeSpace(const unsigned long long size) const {
		return _ld == 0 || _directSize + size <= _ld;
	}

	bool hasFreeSpace(const unsigned long long size) const {
		return _lr == 0 || _size + size <= _lr;
	}

	Directory* getSubDirectory(const string& name) {
		return _directories.at(name);
	}

	unsigned long long getSize(void) const {
		return _size;
	}

	unsigned long long getFileSize(const string& name) const {
		return _files.at(name);
	}

	Directory* createSubDirectory(const string& name) {
		_directories[name] = new Directory();
		return _directories[name];
	}

	void createFile(const string& name, const unsigned long long size) {
		if (hasFile(name)) {
			_directSize -= _files[name];
		}
		_files[name] = size;
		_directSize += size;
	}

	void allocate(const unsigned long long size) {
		_size += size;
	}

	void free(const unsigned long long size) {
		_size -= size;
	}

	void unlinkFile(const string& name) {
		_directSize -= _files[name];
		_files.erase(name);
	}
	
	void unlinkDir(const string& name) {
		delete _directories[name];
		_directories.erase(name);
	}

	bool quota(const unsigned long long ld, const unsigned long long lr) {
		if (0 < ld && ld < _directSize) {
			return false;
		}
		if (0 < lr && lr < _size) {
			return false;
		}
		_ld = ld;
		_lr = lr;
		return true;
	}
};

void _tree(Directory* root, const string& dirname, const unsigned long long indent) {
	cout << string(indent, ' ') << dirname << "(directSize=" << root->_directSize << ", size=" << root->_size << ", ld=" << root->_ld << ", lr=" << root->_lr << ")" << endl;
	for (const auto& file : root->_files) {
		cout << string(indent + 2, ' ') << file.first << "(size=" << file.second << ")" << endl;
	}
	for (const auto& directory : root->_directories) {
		_tree(directory.second, directory.first, indent + 2);
	}
}

class FileSystem {
	Directory _root;

	Directory* _getDirectory(const vector<string>& dirnameParts) {
		Directory* dir = &_root;
		for (const string& dirnamePart : dirnameParts) {
			if (!dir->hasSubDirectory(dirnamePart)) {
				return nullptr;
			}
			dir = dir->getSubDirectory(dirnamePart);
		}
		return dir;
	}
	
	void _allocate(const vector<string>& dirnameParts, const unsigned long long size) {
		Directory* dir = &_root;
		dir->allocate(size);
		for (const string& dirnamePart : dirnameParts) {
			dir = dir->getSubDirectory(dirnamePart);
			dir->allocate(size);
		}
	}

	void _free(const vector<string>& dirnameParts, const unsigned long long size) {
		Directory* dir = &_root;
		dir->free(size);
		for (const string& dirnamePart : dirnameParts) {
			dir = dir->getSubDirectory(dirnamePart);
			dir->free(size);
		}
	}

	bool _checkFreeSpace(const vector<string>& dirnameParts, const unsigned long long size) {
		Directory* dir = &_root;
		if (!dir->hasFreeSpace(size)) {
			return false;
		}
		for (const string& dirnamePart : dirnameParts) {
			dir = dir->getSubDirectory(dirnamePart);
			if (!dir->hasFreeSpace(size)) {
				return false;
			}
		}
		return dir->hasDirectFreeSpace(size);
	}

	Directory* _createDirectories(const vector<string>& dirnameParts, const unsigned long long size) {
		Directory* dir = &_root;
		if (!dir->hasFreeSpace(size)) {
			return nullptr;
		}
		int i;
		for (i = 0; dir->hasSubDirectory(dirnameParts[i]); i++) {
			dir = dir->getSubDirectory(dirnameParts[i]);
			if (!dir->hasFreeSpace(size)) {
				return nullptr;
			}
		}
		if (dir->hasFile(dirnameParts[i])) {
			return nullptr;
		}
		for (; i < dirnameParts.size(); i++) {
			dir = dir->createSubDirectory(dirnameParts[i]);
		}
		return dir;
	}

public:
	bool create(const vector<string>& filepath, unsigned long long size) {
		DEBUG(cout << "create" << endl << "filepath: "; print(filepath); cout << "size: " << size << endl;)
		vector<string> dirnameParts;
		path::dirname(dirnameParts, filepath);
		string basename("");
		path::basename(basename, filepath);

		Directory* dir = _getDirectory(dirnameParts);
		if (dir == nullptr) {
			dir = _createDirectories(dirnameParts, size);
			if (dir == nullptr) {
				return false;
			}
			_allocate(dirnameParts, size);
		} else if (dir->hasFile(basename)) {
		    unsigned long long oldSize = dir->getFileSize(basename);
			if (size > oldSize) {
				if (!_checkFreeSpace(dirnameParts, size - oldSize)) {
					return false;
				}
				_allocate(dirnameParts, size - oldSize);
			} else {
				_free(dirnameParts, oldSize - size);
			}
		} else if (dir->hasSubDirectory(basename)) {
			return false;
		} else {
			if (!_checkFreeSpace(dirnameParts, size)) {
				return false;
			}
			_allocate(dirnameParts, size);
		}
		dir->createFile(basename, size);
		return true;
	}

	bool remove(const vector<string>& filepath) {
		DEBUG(cout << "remove" << endl << "filepath: "; print(filepath);)
		vector<string> dirnameParts;
		path::dirname(dirnameParts, filepath);
		string basename("");
		path::basename(basename, filepath);

		Directory* dir = _getDirectory(dirnameParts);
		if (dir != nullptr) {
		    if (dir->hasFile(basename)) {
		        unsigned long long size = dir->getFileSize(basename);
		        _free(dirnameParts, (unsigned long long) size);
		        dir->unlinkFile(basename);
		    } else if (dir->hasSubDirectory(basename)) {
		        unsigned long long size = dir->getSubDirectory(basename)->getSize();
		        _free(dirnameParts, size);
		        dir->unlinkDir(basename);
		    }
		}
		return true;
	}

	bool quota(const vector<string>& filepath, unsigned long long ld, unsigned long long lr) {
		DEBUG(cout << "quota" << endl << "filepath: "; print(filepath); cout << "ld: " << ld << ", lr: " << lr << endl;)
		Directory* dir = _getDirectory(filepath);
		if (dir == nullptr) {
			return false;
		}
		return dir->quota(ld, lr);
	}

	void tree(void) {
		_tree(&_root, "/", 0);
	}
};

int main() {
	FileSystem fs;

	int n;
	for (cin >> n; n > 0; n--) {
		char op;
		string filepath;
		unsigned long long size;
		unsigned long long ld, lr;

		vector<string> filepathParts;
		bool result = false;

		cin >> op >> filepath;
		path::split(filepathParts, filepath);
		switch (op) {
		case 'C':
			cin >> size;
			result = fs.create(filepathParts, size);
			break;
		case 'R':
			result = fs.remove(filepathParts);
			break;
		case 'Q':
			cin >> ld >> lr;
			result = fs.quota(filepathParts, ld, lr);
			break;
		default:
			break;
		}
		DEBUG(cout << "FileSystem:" << endl; fs.tree();)
		cout << (result ? 'Y' : 'N') << endl;
	}
	return 0;
}

你可能感兴趣的:(C++,c++)