CSP 2020-12

3 带配额的文件系统

tag:复杂模拟 结构体

题面链接

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

题意

  模拟一个文件系统,和我们所用的文件系统类似,是树形结构;不同之处在于,可能会对文件夹有容量限制。对于给定的三种操作:C(存储文件),R(删除文件),Q(设定容量限制),输出操作结果(Y/N)。

思路

   利用结构体进行模拟,每个结点包括:名称(name)、子节点(child)、父节点(parent)、孩子文件配额(ld)、后代文件配额(lr)、孩子文件大小(sizec)、后代文件大小(sizeac)、文件大小(size)、文件类型(type)等属性。
  对于三种操作分别进行模拟,并给出结果。整个程序的思路导图如下图所示。
在这里插入图片描述
  需要特别注意的一点是:当C操作失败时,需要删除新创建的目录文件,否则下次创建同名普通文件时会出错。

附样例的文件系统图:
样例1:
在这里插入图片描述
样例2:
在这里插入图片描述

源码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
    string name="root";//名称
    vector<struct node*> child;//孩子节点指针
    struct node* parent=NULL;//父节点指针
    ll ld=0,lr=0,sizec=0,sizeac=0,size=0;
    // ld:孩子文件配额,lr:后代文件配额,sizec:孩子文件大小,sizeac:后代文件大小,size:普通文件大小
    bool type=false;//文件类型,false:目录文件;true:普通文件。
};

node root;//根节点

//判断p结点及所有祖先结点,后代文件配额是否满足
bool panduan(node *p,ll bianhua){
    if(p==NULL) return true;
    if((p->lr==0 || p->sizeac+bianhua<=p->lr) && panduan(p->parent,bianhua)){//当前结点后代文件配额满足,且所有祖先结点后代文件配额均满足
        p->sizeac+=bianhua;return true;
    }
    else return false;
}

vector<string> v;//保存路径

//C操作
// C /A/B/1 1024
void opec(string s,ll size){
    string dir="";
    //处理字符串,不必考虑v为空的情况
    v.clear();//清空v
    //获取路径
    for(ll i=1;i<s.size();i++){
        if(s[i]=='/'){v.push_back(dir);dir="";continue;}
        dir+=s[i];
    }
    v.push_back(dir);

    node *p=&root;//当前结点指针
    ll len;//长度
    bool isp;//标记
    bool flag=true;//标记目录是否是第一个被创建的
    node *huisu;
    ll ii;
    //处理前面目录
    for(ll i=0;i<v.size()-1;i++){
        len=p->child.size();
        isp=true;
        for(ll j=0;j<len;j++){
            //找到该目录
            if(p->child[j]->name==v[i]){
                //该目录为普通文件,此次操作失败
                if(p->child[j]->type){cout<<"N\n";return;}
                //该目录已存在,进行下层目录查找
                else{
                    p=p->child[j];//修改当前查找结点的指针
                    isp=false;break;
                }
            }
        }
        //没有找到该目录,创建新目录
        if(isp){
            node *n;
            n=new node;
            n->name=v[i];
            n->parent=p;
            //记录新创建目录的起点,以便于删除
            if(flag){
                flag= false;
                huisu=p;
                ii=len;
            }
            p->child.push_back(n);
            p=n;//修改当前查找结点的指针
        }
    }
    //处理最后的普通文件
    len=p->child.size();
    //判断该文件是否已存在
    for(ll i=0;i<len;i++){
        //该文件已存在
        if(p->child[i]->name==v[v.size()-1]){
            //该文件为目录文件,操作失败
            if(p->child[i]->type== false) {cout<<"N\n";return;}
            //该文件为普通文件
            ll bianhua=p->child[i]->size-size;//变化值:旧文件-新文件
            //大小未变化,直接返回
            if(bianhua==0){cout<<"Y\n";return;}
            //新文件大小<旧文件,直接更新
            else if(bianhua>0){
                p->child[i]->size=size;
                p->sizec-=bianhua;//更新父节点的孩子文件大小
                //更新所有祖先节点的后代文件大小
                while(p!=NULL){
                    p->sizeac-=bianhua;
                    p=p->parent;
                }
                cout<<"Y\n";return;
            }
            //新文件大小>旧文件,判断是否超过配额
            else{
                bianhua*=-1;
                //满足配额
                if((p->ld==0 || p->sizec+bianhua<=p->ld) && panduan(p,bianhua)){//孩子文件配额,后代文件配额均满足时
                    p->child[i]->size=size;//更新文件大小
                    p->sizec+=bianhua;//更新父节点,孩子文件大小
                    cout<<"Y\n";return;
                }
                    //不满足
                else{cout<<"N\n";return;}
            }
        }
    }
    //该文件不存在,创建新文件
    //满足配额
    if((p->ld==0 || p->sizec+size<=p->ld) && panduan(p,size)){//孩子文件配额,后代文件配额均满足时
        p->sizec+=size;
        node *n;
        n=new node;
        n->name=v[v.size()-1];
        n->size=size;
        n->type= true;//普通文件
        n->parent=p;
        p->child.push_back(n);
        cout<<"Y\n";return;
    }
    //不满足
    else{
        //删除已创建目录***********************************
        if(flag==false){huisu->child.erase(huisu->child.begin()+ii);}
        cout<<"N\n";return;
    }
}

//R操作
// R /A/B
void oper(string s){
    string dir="";
    //处理字符串,不必考虑v为空的情况
    v.clear();//清空v
    //获取路径
    for(ll i=1;i<s.size();i++){
        if(s[i]=='/'){v.push_back(dir);dir="";continue;}
        dir+=s[i];
    }
    v.push_back(dir);

    node *p=&root;//当前结点指针
    ll len;//长度
    bool isp;//标记
    //处理前面目录
    for(ll i=0;i<v.size()-1;i++){
        len=p->child.size();
        isp=true;
        for(ll j=0;j<len;j++){
            //找到该目录
            if(p->child[j]->name==v[i]){
                //该目录为普通文件,返回
                if(p->child[j]->type){cout<<"Y\n";return;}
                //该目录存在,进行下层目录查找
                else{
                    p=p->child[j];//修改当前查找结点的指针
                    isp=false;break;
                }
            }
        }
        //没有找到该目录,返回
        if(isp){cout<<"Y\n";return;}
    }
    //处理最后的普通文件 or 目录文件
    len=p->child.size();
    //判断该文件是否存在
    for(int i=0;i<len;i++){
        //该文件存在
        if(p->child[i]->name==v[v.size()-1]){
            //该文件为目录
            if(p->child[i]->type== false){
                ll size=p->child[i]->sizeac;//目录的所有后代文件大小
                p->child.erase(p->child.begin()+i);//删除此节点
                //所有祖先结点的后代文件大小减去size
                while(p!=NULL){
                    p->sizeac-=size;
                    p=p->parent;
                }
                cout<<"Y\n";return;
            }
            //该文件为普通文件
            else{
                ll size=p->child[i]->size;
                p->child.erase(p->child.begin()+i);//删除此节点
                p->sizec-=size;//父结点的孩子文件大小减去size
                //所有祖先结点的后代文件大小减去size
                while(p!=NULL){
                    p->sizeac-=size;
                    p=p->parent;
                }
                cout<<"Y\n";return;
            }
        }
    }
    //该文件不存在,返回
    cout<<"Y\n";return;
}

//Q操作
//Q / 0 1
void opeq(string s,ll ld,ll lr){
    string dir="";
    //处理字符串,需要考虑v为空的情况
    v.clear();//清空v
    //获取路径
    for(ll i=1;i<s.size();i++){
        if(s[i]=='/'){v.push_back(dir);dir="";continue;}
        dir+=s[i];
    }
    v.push_back(dir);

    node* p=&root;//当前结点指针
    if(v[0]==""){//对根节点的操作
        //满足配额
        if((ld==0 || p->sizec<=ld) && (lr==0 || p->sizeac<=lr)){
            p->ld=ld;p->lr=lr;
            cout<<"Y\n";return;
        }
        //不满足
        else{cout<<"N\n";return;}
    }
    int len;//长度
    bool isp;//标记
    //处理目录
    for(ll i=0;i<v.size();i++){
        len=p->child.size();
        isp=true;
        for(ll j=0;j<len;j++){
            //找到该目录
            if(p->child[j]->name==v[i]){
                //该目录为普通文件,此次操作失败
                if(p->child[j]->type){cout<<"N\n";return;}
                //该目录已存在,进行下层目录查找
                else{
                    p=p->child[j];//修改当前查找结点的指针
                    //最后一个文件时,进行配额判断
                    if(i==v.size()-1){
                        //满足配额
                        if((ld==0 || p->sizec<=ld) && (lr==0 || p->sizeac<=lr)){
                            p->ld=ld;p->lr=lr;
                            cout<<"Y\n";return;
                        }
                        //不满足
                        else{cout<<"N\n";return;}
                    }
                    isp=false;break;
                }
            }
        }
        //没有找到该目录,此次操作失败
        if(isp){cout<<"N\n";return;}
    }
}
int main() {
    ll n;
    string s;
    ll size1,size2;
    char c;
    cin>>n;
    while(n--){
        cin>>c;
        switch(c){
            case 'C':
                cin>>s>>size1;
                opec(s,size1);
                break;
            case 'R':
                cin>>s;
                oper(s);
                break;
            case 'Q':
                cin>>s>>size1>>size2;
                opeq(s,size1,size2);
                break;
        }
    }
    return 0;
}
/*
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

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

10
C /A/B 1
Q /A 2 2
C /A/C/D 1024
C /A/C 1
Q /A 0 0
C /A/C 1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值