题目背景

小 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. 【并发编程】- 内存模型(针对JSR-133内存模型)篇

    并发编程模型 1.两个关键问题 1)线程之间如何通信 共享内存 程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信 消息传递 程之间没有公共状态,线程之间必须通过发送消息来显式进行通信 ...

  2. .NET 云原生架构师训练营(模块二 基础巩固 MongoDB API重构)--学习笔记

    2.5.8 MongoDB -- API重构 Lighter.Domain Lighter.Application.Contract Lighter.Application LighterApi Li ...

  3. 风炫安全WEB安全学习第十八节课 使用SQLMAP自动化注入(二)

    风炫安全WEB安全学习第十八节课 使用SQLMAP自动化注入(二) –is-dba 当前用户权限(是否为root权限) –dbs 所有数据库 –current-db 网站当前数据库 –users 所有 ...

  4. 地图开发笔记(一):百度地图介绍、使用和Qt内嵌地图Demo

    前言   Qt在地图方面的研发.   百度地图 介绍   百度的地图分为多个开发,都是在线的(离线的需要自己提取,本篇解说在线地图).  百度地图JavaScript API支持HTTP和HTTPS, ...

  5. Head First 设计模式 —— 09. 模版方法 (Template Method) 模式

    模板方法模式 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. P289 特点 主导算法框架,并且保护这个算法 P28 ...

  6. Nginx+FFmpeg实现RTSP转RTMP

    RTSP转RTMP 本次转流采用Centos+Nginx+FFmpeg实现,具体实现如下: 1. 安装Ngxin 安装详细略(可以选择安装阿里的Tengine,官方[下载路径](Download - ...

  7. 【原创】X86_64汇编、寄存器、内嵌汇编

    整理的X86_64/X86汇编.寄存器.C内嵌汇编笔记,主要用于查阅使用. 目录 一.汇编语言 二.指令 数据传输指令 栈操作指令 push pop 运算指令 位操作 比较操作指令 标志寄存器 流控制 ...

  8. JS navigator.userAgent

    var u = navigator.userAgent; var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > - ...

  9. 【Linux】make编译的小技巧

    ------------------------------------------------------------------------------------------------- | ...

  10. 图像分割论文 | DRN膨胀残差网络 | CVPR2017

    文章转自:同作者个人微信公众号[机器学习炼丹术].欢迎交流沟通,共同进步,作者微信:cyx645016617 论文名称:'Dilated Residual Networks' 论文链接:https:/ ...