题目背景

小 H 同学发现,他维护的存储系统经常出现有人用机器学习的训练数据把空间占满的问题,十分苦恼。

查找了一阵资料后,他想要在文件系统中开启配额限制,以便能够精确地限制大家在每个目录中最多能使用的空间。

文件系统概述

文件系统,是一种树形的文件组织和管理方式。

在文件系统中,文件是指用名字标识的文件系统能够管理的基本对象,分为普通文件目录文件两种,目录文件可以被简称为目录。目录中有一种特殊的目录被叫做根目录

除了根目录外,其余的文件都有名字,称为文件名

合法的文件名是一个由若干数字([0-9])、大小写字母([A-Za-z])组成的非空字符串。

普通文件中含有一定量的数据,占用存储空间;目录不占用存储空间。

文件和目录之间存在含于关系。

上述概念满足下列性质:

  1. 有且仅有一个根目录
  2. 对于除根目录以外的文件,都含于且恰好含于一个目录;
  3. 含于同一目录的文件,它们的文件名互不相同;
  4. 对于任意不是根目录的文件 f,若 f 不含于根目录,那么存在有限个目录 d1,d2,…,dn,

    使得 f 含于 d1,d1 含于 d2,…,dn 含于根目录。

结合性质 4 和性质 2 可知,性质 4 中描述的有限多个目录,即诸 di,是唯一的。再结合性质 3,我们即可通过从根目录开始的一系列目录的序列,来唯一地指代一个文件。

我们记任意不是根目录且不含于根目录的文件 f 的文件名是 Nf,那么 f 的路径 是:‘/′+Ndn+‘/′+⋯+Nd1+‘/′+Nf,其中符号 + 表示字符串的连接;对于含于根目录的文件 f,它的路径是:‘/′+Nf;根目录的路径是:‘/′。不符合上述规定的路径都是非法的。例如:/A/B是合法路径,但 /A//B/A/A/A/B 都不是合法路径。

若文件 f 含于目录 d,我们也称 f 是 d 的孩子文件。d 是 f 的双亲目录

我们称文件 f 是目录 d 的后代文件,如果满足:(1) f 是 d 的孩子文件,或(2)f 含于 d 的后代文件。

如图所示,该图中绘制的文件系统共有 8 个文件。其中,方形表示目录文件,圆形表示普通文件,它们之间的箭头表示含于关系。在表示文件的形状上的文字是其文件名;各个形状的左上方标记了序号,以便叙述。在该文件系统中,文件 5 含于文件 2,文件 5 是文件 2 的孩子文件,文件 5 也是文件 2 的后代文件。文件 8 是文件 2 的后代文件,但不是文件 2 的孩子文件。文件 8 的路径是 /D1/D1/F2

配额概述

配额是指对文件系统中所含普通文件的总大小的限制。

对于每个目录 d,都可以设定两个配额值:目录配额后代配额

我们称目录配额 LDd 是满足的,当且仅当 d 的孩子文件中,全部普通文件占用的存储空间之和不大于该配额值。

我们称后代配额 LRd是满足的,当且仅当 d 的后代文件中,全部普通文件占用的存储空间之和不大于该配额值。

我们称文件系统的配额是满足的,当且仅当该文件系统中所有的配额都是满足的。

很显然,若文件系统中仅存在目录,不存在普通文件,那么该文件系统的配额一定是满足的。随着配额和文件的创建,某个操作会使文件系统的配额由满足变为不满足,这样的操作会被拒绝。例如:试图设定少于目前已有文件占用空间的配额值,或者试图创建超过配额值的文件。

题目描述

在本题中,假定初始状态下,文件系统仅包含根目录。你将会收到若干对文件系统的操作指令。对于每条指令,你需要判断该指令能否执行成功,对于能执行成功的指令,在成功执行该指令后,文件系统将会被相应地修改。对于不能执行成功的指令,文件系统将不会发生任何变化。你需要处理的指令如下:

创建普通文件

创建普通文件指令的格式如下:

C <file path> <file size>

创建普通文件的指令有两个参数,是空格分隔的字符串和一个正整数,分别表示需要创建的普通文件的路径和文件的大小。

对于该指令,若路径所指的文件已经存在,且也是普通文件的,则替换这个文件;若路径所指文件已经存在,但是目录文件的,则该指令不能执行成功。

当路径中的任何目录不存在时,应当尝试创建这些目录;若要创建的目录文件与已有的同一双亲目录下的孩子文件中的普通文件名称重复,则该指令不能执行成功。

另外,还需要确定在该指令的执行是否会使该文件系统的配额变为不满足,如果会发生这样的情况,则认为该指令不能执行成功,反之则认为该指令能执行成功。

移除文件

移除文件指令的格式如下:

R <file path>

移除文件的指令有一个参数,是字符串,表示要移除的文件的路径。若该路径所指的文件不存在,则不进行任何操作。若该路径所指的文件是目录,则移除该目录及其所有后代文件。

在上述过程中被移除的目录(如果有)上设置的配额值也被移除。

该指令始终认为能执行成功。

设置配额值

Q <file path> <LD> <LR>

设置配额值的指令有三个参数,是空格分隔的字符串和两个非负整数,分别表示需要设置配额值的目录的路径、目录配额和后代配额。

该指令表示对所指的目录文件,分别设置目录配额和后代配额。若路径所指的文件不存在,或者不是目录文件,则该指令执行不成功。

若在该目录上已经设置了配额,则将原配额值替换为指定的配额值。

特别地,若配额值为 0,则表示不对该项配额进行限制。若在应用新的配额值后,该文件系统配额变为不满足,那么该指令执行不成功。

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 n,表示需要处理的指令条数。

输入接下来会有 n 行,每一行一个指令。指令的格式符合前述要求。输入数据保证:对于所有指令,输入的路径是合法路径;对于创建普通文件和移除文件指令,输入的路径不指向根目录。

输出格式

输出到标准输出。

输出共有 n 行,表示相应的操作指令是否执行成功。若成功执行,则输出字母 Y;否则输出 N

样例1输入

10
C /A/B/1 1024
C /A/B/2 1024
C /A/B/1/3 1024
C /A 1024
R /A/B/1/3
Q / 0 1500
C /A/B/1 100
Q / 0 1500
R /A/B
Q / 0 1

样例1输出

Y
Y
N
N
Y
N
Y
Y
Y
Y

样例1解释

输入总共有 10 条指令。

其中前两条指令可以正常创建两个普通文件。

第三条指令试图创建 /A/B/1/3,但是 /A/B/1 已经存在,且不是目录,而是普通文件,不能再进一步创建孩子文件,因此执行不成功。

第四条指令试图创建 /A,但是 /A 已经存在,且是目录,因此执行不成功。

第五条指令试图删除 /A/B/1/3,由于该文件不存在,因此不对文件系统进行修改,但是仍然认为执行成功。

第六条指令试图在根目录增加后代配额限制,但此时,文件系统中的文件总大小是 2048,因此该限制无法生效,执行不成功。

第七条指令试图创建文件 /A/B/1,由于 /A/B/1 已经存在,且是普通文件,因此该指令实际效果是将原有的该文件替换。

此时文件总大小是 1124,因此第八条指令就可以执行成功了。

第九条指令递归删除了 /A/B 目录和它的所有后代文件。

此时文件系统中已经没有普通文件,因此第十条命令可以执行成功。

样例2输入

9
Q /A/B 1030 2060
C /A/B/1 1024
C /A/C/1 1024
Q /A/B 1024 0
Q /A/C 0 1024
C /A/B/3 1024
C /A/B/D/3 1024
C /A/C/4 1024
C /A/C/D/4 1024

样例2输出

N
Y
Y
Y
Y
N
Y
N
N

样例2解释

输入共有 9 条指令。

第一条指令试图为 /A/B 创建配额规则,然而该目录并不存在,因此执行不成功。

接下来的两条指令创建了两个普通文件。再接下来的两条指令分别在目录 /A/B/A/C 创建了两个配额规则。其中前者是目录配额,后者是后代配额。

接下来的两条指令,创建了两个文件。其中,/A/B/3 超出了在 /A/B 的目录配额,因此执行不成功;但 /A/B/D/3

不受目录配额限制,因此执行成功。

最后两条指令,创建了两个文件。虽然在 /A/C没有目录配额限制,但是无论是 /A/C 下的孩子文件还是后代文件,都受到后代配额的限制,因此两条指令执行都不成功。

子任务

本题目各个测试点的数据规模如下:

表格中,目录层次是指各指令中出现的路径中,/ 字符的数目。

所有输入的数字均不超过\(10^{18}\)。

转载:https://blog.csdn.net/weixin_43693379/article/details/112725802

代码

#include<iostream>
#include<algorithm>
#include<map>
#include<vector> using namespace std;
const int N = 5e6 + 10;
typedef long long ll;
//LDd目录配额,LRd后代配额,LD现有目录额,LR现有后代额
struct node {
map<string, int> branch; //每个目录节点的孩子节点(包括目录节点和普通文件)
int isleaf; //是否是普通文件
ll LDd, LRd; //目录配额,后代配额
ll LD, LR; //现有目录,后代
ll val; //普通文件的大小
int fa; //父节点编号
};
node tr[N];
int vex; //有效文件名所属编号
string getindex(string &s, int &num) //截取一个合法文件名
{
string res = "";
int i;
for (i = num; s[i] != '/' && i < s.size(); i++)
res += s[i];
num = i + 1;
return res;
} vector<pair<int, string> > v; void del() //若插入失败,对本次前面所有插入操作进行撤销
{ for (int i = 0; i < v.size(); i++) { int a = v[i].first;
string b = v[i].second;
tr[a].branch.erase(tr[a].branch.find(b));
}
} bool insert(string s, ll size) //文件插入
{
v.clear();
int num = 1, fa = 0, init = vex, len = s.size();
while (num < len) //直至截取最后一个文件名
{
string ss = getindex(s, num);
//如果要创建的目录文件与已有的同一双亲目录下的孩子文件中的普通文件名称重复,则该指令不能执行成功
if (tr[fa].branch[ss] && tr[tr[fa].branch[ss]].isleaf && num < len) {
vex = init;
del();
return false;
}
int id, flag = 0;
if (tr[fa].branch[ss])
id = tr[fa].branch[ss], flag = 1;
else //若不存在该目录/普通文件,进行创建
id = ++vex, tr[vex].isleaf = 0, tr[vex].fa = fa, tr[vex].LDd = 0, tr[vex].LRd = 0, tr[fa].branch[ss] = vex, v.push_back(
make_pair(fa, ss));
if (num < len)
fa = id;
if (num >= len) //遍历至叶子文件时
{
ll extra; //需要更新的文件值
if (flag) //叶子文件如果已存在
{
if (!tr[id].isleaf) //如果是个目录文件,插入失败
{
vex = init;
del();
return false;
}
extra = size - tr[id].val;
} else
extra = size;
if (tr[fa].LD + extra > tr[fa].LDd && tr[fa].LDd) //如果双亲目录的目录配额存在且因为插入该文件超额,插入失败
{
vex = init;
del();
return false;
}
tr[id].val = size;
tr[id].LR = size;
tr[id].isleaf = 1;
for (int r = fa; r != -1; r = tr[r].fa)
if (tr[r].LR + extra > tr[r].LRd && tr[r].LRd) //如果后代配额存在且会因为插入此文件超额,插入失败
{
vex = init;
del();
return false;
}
for (int r = fa; r != -1; r = tr[r].fa) //插入成功,更新整条路径
tr[r].LR += extra;
tr[fa].LD += extra;
} }
return true;
} void remove(string s) //移除文件
{
int num = 1, fa = 0, len = s.size();
while (num < len) {
string ss = getindex(s, num);
if (!tr[fa].branch[ss]) return; //若路径不存在,直接返回
int id = tr[fa].branch[ss];
if (num < len)
fa = id;
if (num < len && tr[id].isleaf) //如果路径不合法,返回
return;
if (num >= len) {
tr[fa].branch.erase(tr[fa].branch.find(ss)); //删除与双亲节点之间的路径
for (int r = fa; r != -1; r = tr[r].fa) //更新前面祖宗节点的后代配额
tr[r].LR -= tr[id].LR;
if (tr[id].isleaf) //若删除节点为叶子节点,更新双亲节点的目录配额
tr[fa].LD -= tr[id].LR;
}
}
} bool set(string s, ll ld, ll lr) //设置配置额
{
if (s.size() == 1) //配置根目录
{
int id = 0;
if ((ld < tr[id].LD && ld) || (lr < tr[id].LR && lr)) //如果配置额小于当前已存在的文件大小,配置失败
return false;
tr[id].LRd = lr;
tr[id].LDd = ld;
return true;
}
int num = 1, fa = 0, len = s.size();
while (num < len) {
string ss = getindex(s, num);
if (!tr[fa].branch[ss]) return false; //如果路径不存在,配置失败
int id = tr[fa].branch[ss];
fa = id;
if (tr[id].isleaf) return false; //如果配置的不是目录文件,配置失败
if (num >= len) {
if ((ld < tr[id].LD && ld) || (lr < tr[id].LR && lr)) //如果配置额小于当前已存在的文件大小,配置失败
return false;
tr[id].LRd = lr;
tr[id].LDd = ld; //修改额度,配置成功
return true;
}
}
} int main() {
ios::sync_with_stdio(false);
cin.tie(0);
string s;
int n;
cin >> n;
tr[0].fa = -1;
tr[0].isleaf = 0;
tr[0].LDd = 0;
tr[0].LRd = 0;
while (n--) {
bool flag = true;
char order;
cin >> order;
ll ld, lr, size;
switch (order) {
case 'C':
cin >> s >> size;
flag = insert(s, size);
break;
case 'R':
cin >> s;
remove(s);
break;
case 'Q':
cin >> s >> ld >> lr;
flag = set(s, ld, lr);
break;
}
if (flag)
cout << "Y" << '\n';
else
cout << "N" << '\n';
}
return 0;
}

CCF CSP 202012-3 文件配额的更多相关文章

  1. CCF CSP 201604-3 路径解析

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201604-3 路径解析 问题描述 在操作系统中,数据通常以文件的形式存储在文件系统中.文件系 ...

  2. CCF CSP/CCSP报名费优惠的方法以及常见疑问

    目录 1. 本文地址 2. 认证作用 2.1. 高校认可 2.2. 赛事认可 2.3. 企业认可 3. 报名费价格及获取优惠的方法 3.1. CCF CSP 3.2. CCF CCSP 4. 语言与I ...

  3. CCF CSP 认证

    参加第八次CCF CSP认证记录 代码还不知道对不对,过两天出成绩. 成绩出来了,310分. 100+100+100+10+0: 考试13:27开始,17:30结束,提交第4题后不再答题,只是检查前四 ...

  4. CCF CSP 201609-2 火车购票

    题目链接:http://118.190.20.162/view.page?gpid=T46 问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配. 假设一节车厢有20排.每一排 ...

  5. CCF CSP 201703-3 Markdown

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201703-3 Markdown 问题描述 Markdown 是一种很流行的轻量级标记语言(l ...

  6. CCF CSP 201703

    CCF CSP 2017·03 做了一段时间的CCF CSP试题,个人感觉是这样分布的 A.B题基本纯暴力可满分 B题留心数据范围 C题是个大模拟,留心即可 D题更倾向于图论?(个人做到的D题基本都是 ...

  7. CCF CSP 201312-3 最大的矩形

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201312-3 最大的矩形 问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i( ...

  8. CCF CSP 201609-3 炉石传说

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201609-3 炉石传说 问题描述 <炉石传说:魔兽英雄传>(Hearthston ...

  9. CCF CSP 201403-3 命令行选项

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201403-3 命令行选项 问题描述 请你写一个命令行分析程序,用以分析给定的命令行里包含哪些 ...

  10. CCF CSP 201709-4 通信网络

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201709-4 通信网络 问题描述 某国的军队由N个部门组成,为了提高安全性,部门之间建立了M ...

随机推荐

  1. elasticsearch迁移工具--elasticdump的使用

    这篇文章主要讨论使用Elasticdump工具做数据的备份和type删除. Elasticsearch的备份,不像MYSQL的myslqdump那么方便,它需要一个插件进行数据的导出和导入进行备份和恢 ...

  2. 阿里面试:MySQL如何设计索引更高效?

    有情怀,有干货,微信搜索[三太子敖丙]关注这个不一样的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系列文章. ...

  3. App控件定位

    本文将分享Android相关基础知识和Android APP控件定位工具的使用方法. Android基础知识 Android布局 Android是通过容器的布局属性来管理子控件的位置关系(iOS去掉了 ...

  4. wpf 中用 C# 代码创建 PropertyPath ,以对间接目标进行 Storyboard 动画.

    如图,一个 Rectangle 一个 Button ,点击按钮时要通过动画完成对 Rectangle填充色的渐变动画. Xaml: 1 <Window 2 x:Class="WpfAp ...

  5. 创建mysql帐户

    CREATE USER 'username'@'host' IDENTIFIED BY 'password';

  6. .NET 云原生架构师训练营(模块二 基础巩固 Scrum 团队)--学习笔记

    2.7.3 Scrum 团队 理想的环境 团队章程 如何组建 Scrum 团队 产品待办事项列表 用户故事 敏捷开发流程 理想的环境 5-9人 100% 跨职能 在一起 自组织 自组织 目标 授权 沟 ...

  7. windows下如何安装Python、pandas

    windows下如何安装Python.pandas 本篇主要涵盖以下三部分内容: Python.Pycharm的安装 使用Pycharm创建.运行Python程序 安装pandas 1.Python. ...

  8. Tensorflow-线性回归与手写数字分类

    线性回归 步骤 构造线性回归数据 定义输入层 设计神经网络中间层 定义神经网络输出层 计算二次代价函数,构建梯度下降 进行训练,获取预测值 画图展示 代码 import tensorflow as t ...

  9. SpringCloud zuul 网关限流分析

    最近项目中 spring cloud zuul 运用到限流功能,打算配置一下就直接使用,不过在压测与调优过程中遇到一些没有预测到的问题,附上排查与解析结果 yml.pom配置 强烈推荐,按最新gith ...

  10. babel : 无法加载文件 C:\Users\win\AppData\Roaming\npm\babel.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/ go.micros

    babel报错:babel : 无法加载文件 C:\Users\win\AppData\Roaming\npm\babel.ps1,因为在此系统上禁止运行脚本.有关详细信息,请参阅 https:/ g ...