CSP202012-3

字符串处理一直以来是我的弱项,趁着下一次考试前认真做了一下上次考试的模拟题。
我自己完全没有思路,参考了一位大牛的博客,地址在这里。这题真的很细节,做完以后我有几点反思:1.如何定义数据结构真的很关键。2.真的要非常细心,有些我自己写的bug是我对照着大牛的代码才发现的。3.要熟练掌握C++的string。
下面是代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
/*节点的数据结构*/
typedef struct Node
{
    int father;//父节点
    map<string,int> child;//孩子节点
    int type;//文件类型,1代表普通文件,2代表目录文件
    ll ld,lr;//目录配额,后代配额
    ll ld_r,lr_r;//实际目录配额,实际后代配额
    ll size;//如果是普通文件的话,文件大小
}Node;
vector<pair<int,string>> reback;//用于执行撤销操作的容器
Node node[4000010];
int num=0;//存储文件节点的数组的下标,0代表根目录节点
/*回滚函数
当执行C命令是需要创建目录,如果发生错误需要回滚*/
void Reback()
{
    for(int i=0;i<reback.size();i++)
    {
        int id=reback[i].first;
        string name=reback[i].second;
        node[id].child.erase(node[id].child.find(name));
    }
}
/*创建普通文件的函数*/
string CommandC()
{
    string path;
    ll filesize;
    cin>>path>>filesize;
    int last=-1;
    for(int i=path.length()-1;i>=0;i--)
    {
        if(path[i]=='/')
        {
            last=i;
            break;
        }
    }
    int current=1;
    int id=0;
    reback.clear();
    int oldnum=num;
    /*处理目录文件*/
    while(current<last)
    {
        string t="";
        while(current<last&&path[current]!='/')
        {
            t+=path[current];
            current++;
        }
        current++;
        if(node[id].child.find(t)==node[id].child.end())//目录文件不存在,创建新文件
        {
            num++;
            node[id].child[t]=num;
            node[num].father=id;
            node[num].type=2;
            node[num].ld=LLONG_MAX/3;
            node[num].lr=LLONG_MAX/3;
            reback.push_back(make_pair(id,t));
            id=num;
        }
        else
        {
            int childid=node[id].child[t];
            if(node[childid].type==1)//已经存在同名普通文件
            {
                num=oldnum;
                Reback();
                return "N";
            }
            id=childid;
        }
    }
    /*对普通文件的处理*/
    string t="";
    for(int i=last+1;i<path.length();i++)
    {
        t+=path[i];
    }
    if(node[id].child.find(t)!=node[id].child.end())//文件已存在
    {
        int childid=node[id].child[t];
        if(node[childid].type==2)
        {
            num=oldnum;
            Reback();
            return "N";
        }
    }
    /*判断新的改变是否满足配额要求*/
    ll changesize=0;
    if(node[id].child.find(t)==node[id].child.end()) changesize=filesize;//如果文件不存在,则新增大小为文件大小
    else
    {
        int fileid=node[id].child[t];
        changesize=-node[fileid].size+filesize;
    }
    /*检查是否满足目录配额*/
    if(node[id].ld_r+changesize>node[id].ld)
    {
        num=oldnum;
        Reback();
        return "N";
    }
    int now=id;
    /*检查对于所有的父目录,是否满足后代配额*/
    while(now!=-1)
    {
        if(node[now].lr_r+changesize>node[now].lr)
        {
            num=oldnum;
            Reback();
            return "N";
        }
        now=node[now].father;
    }
    if(node[id].child.find(t)==node[id].child.end())//如果文件不存在,则需要创建
    {
        num++;
        node[num].type=1;
        node[num].father=id;
        node[num].size=filesize;
        node[id].child[t]=num;
    }
    else
    {
        node[node[id].child[t]].size=filesize;
    }
    node[id].ld_r=node[id].ld_r+changesize;
    now=id;
    while(now!=-1)
    {
        node[now].lr_r=node[now].lr_r+changesize;
        now=node[now].father;
    }
    return "Y";
}
/*执行更改配额的函数*/
string CommandQ()
{
    string filepath;
    ll LD,LR;
    cin>>filepath>>LD>>LR;
    int last=-1;
    int id=0;
    for(int i=filepath.length()-1;i>=0;i--)
    {
        if(filepath[i]=='/')
        {
            last=i;
            break;
        }
    }
    int current=1;
    if(LD==0) LD=LLONG_MAX/3;
    if(LR==0) LR=LLONG_MAX/3;
    /*处理路径上的目录文件*/
    while(current<last)
    {
        string t="";
        while(current<last&&filepath[current]!='/')
        {
            t+=filepath[current];
            current++;
        }
        current++;
        if(node[id].child.find(t)==node[id].child.end())//目录不存在
        {
            return "N";
        }
        else
        {
            id=node[id].child[t];
            if(node[id].type==1) return "N";
        }
    }
    /*处理目标目录*/
    string t="";
    for(int i=last+1;i<filepath.length();i++)
    {
        t+=filepath[i];
    }
    if(t=="") id=0;//根目录
    else
    {
        if(node[id].child.find(t)==node[id].child.end()) return "N";
        else
        {
            id=node[id].child[t];
        }
    }
    if(node[id].type==1) return "N";
    if(node[id].ld_r>LD||node[id].lr_r>LR) return "N";
    else
    {
        node[id].ld=LD;
        node[id].lr=LR;
        return "Y";
    }
}
/*处理删除文件的命令*/
string CommandR()
{
    string filepath;
    cin>>filepath;
    int last=-1;
    int current=1;
    int id=0;
    for(int i=filepath.length()-1;i>=0;i--)
    {
        if(filepath[i]=='/')
        {
            last=i;
            break;
        }
    }
    while(current<last)
    {
        string t="";
        while(current<last&&filepath[current]!='/')
        {
            t+=filepath[current];
            current++;
        }
        current++;
        if(node[id].child.find(t)==node[id].child.end()) return "Y";
        else
        {
            id=node[id].child[t];
        }
        if(node[id].type==1) return "Y";
    }
    string t="";
    for(int i=last+1;i<filepath.length();i++)
        t+=filepath[i];
    if(node[id].child.find(t)==node[id].child.end()) return "Y";
    int delnode=node[id].child[t];
    ll delsize;
    if(node[delnode].type==1)
    {
        delsize=node[delnode].size;
        node[id].ld_r-=delsize;
        node[id].child.erase(node[id].child.find(t));
    }
    else if(node[delnode].type==2)
    {
        delsize=node[delnode].lr_r;
        node[id].child.erase(node[id].child.find(t));
    }
    int now=id;
    while(now!=-1)
    {
        node[now].lr_r-=delsize;
        now=node[now].father;
    }
    return "Y";
}
int main()
{
    node[0].father=-1;
    node[0].type=2;
    node[0].ld=LLONG_MAX/3;
    node[0].lr=LLONG_MAX/3;
    int N;
    cin>>N;
    char a;
    for(int i=0;i<N;i++)
    {
        cin>>a;
        switch(a)
        {
            case 'C':cout<<CommandC()<<endl;break;
            case 'Q':cout<<CommandQ()<<endl;break;
            case 'R':cout<<CommandR()<<endl;break;
        }
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值