1.解题思路
感觉算是csp第三题中比较复杂的情况了,插入需考虑文件路径是否存在,不存在且其双亲文件下无同名的普通文件才能创建新文件,存在但为目录文件执行失败,执行失败都要进行回溯删除之前的插入操作,存在且为普通文件且满足配额要求的可以进行替换同时更新配额值,删除需考虑文件不存在和文件是目录/普通文件的情况并进行相应配额值的更新,配额需考虑路径不存在、非目录文件以及能否进行配额替换等情况。
详细思路请见代码注释
2.满分代码
#include<iostream>
#include<string.h>
#include<vector>
#include<map>
#include<utility>
using namespace std;
typedef long long ll;
const int N=5e6+6;
struct file{
map<string,int>child;//孩子文件名--孩子节点编号
int type;//0--目录 1--文件
ll size;//大小
ll LD,LR;//孩子 后代配额
ll ld,lr;//孩子文件/后代文件所占大小
int father;//双亲节点编号
}tr[N];
int n;
string getname(string str,int &num)//以/为分隔符 提取每一层文件名
{
string res="";
int len=str.size();
int i;
for(i=num;str[i]!='/'&&i<len;i++)
{
res+=str[i];
}
num=i+1;
return res;
}
vector<pair<int,string>>v;//文件编号--文件名
int vex;
void del()//插入失败时删除
{
for(int i=0;i<v.size();i++)
{
int index=v[i].first;
string fname=v[i].second;
tr[index].child.erase(tr[index].child.find(fname));
}
}
bool insert(string s,ll size)//插入
{
v.clear();
int back=vex,num=1,fa=0,len=s.size();
while(num<len)
{
string fname=getname(s,num);
if(tr[fa].child[fname]&&tr[tr[fa].child[fname]].type&&num<len)//存在与该目录同名的普通文件
{
vex=back;
del();
return false;
}
int id,flag=0;
if(tr[fa].child[fname])//该文件已存在
{
id=tr[fa].child[fname];
flag=1;
}
else//不存在则创建
{
id=++vex;
tr[id].type=0;
tr[id].father=fa;
tr[id].LD=tr[id].LR=0;
tr[fa].child[fname]=id;
v.push_back(make_pair(fa,fname));
}
if(num<len)
fa=id;
if(num>=len)//到达叶子节点
{
ll addsize=0;
if(flag)//文件存在
{
if(!tr[id].type)//是目录文件
{
vex=back;
del();
return false;
}
addsize=size-tr[id].size;
}
else
addsize=size;
if(addsize+tr[fa].ld>tr[fa].LD&&tr[fa].LD)//该文件不满足双亲文件的孩子配额要求
{
vex=back;
del();
return false;
}
tr[id].size=size;
tr[id].type=1;
tr[id].lr=size;
for(int i=fa;i!=-1;i=tr[i].father)//该文件是否满足其双亲及祖先文件的后代配额要求
{
if(tr[i].lr+addsize>tr[i].LR&&tr[i].LR)
{
vex=back;
del();
return false;
}
}
for(int i=fa;i!=-1;i=tr[i].father)//更新
{
tr[i].lr+=addsize;
}
tr[fa].ld+=addsize;
}
}
return true;
}
void remove(string s)//移除
{
int fa=0;
int num=1;
int len=s.size();
while(num<len)
{
string fname=getname(s,num);
if(tr[fa].child.find(fname)==tr[fa].child.end())return;//文件路径不存在
int id=tr[fa].child[fname];
if(num<len)
fa=id;
if(num<len&&tr[id].type)return;//不合法的路径
if(num>=len)//到达叶子节点
{
tr[fa].child.erase(tr[fa].child.find(fname));//删除该文件
for(int i=fa;i!=-1;i=tr[i].father)//更新该文件的双亲及祖先文件 的lr值
{
tr[i].lr-=tr[id].lr;
}
if(tr[id].type)//若该文件为普通文件 还需更新该文件双亲文件的ld值
tr[fa].ld-=tr[id].lr;
}
}
}
bool config(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].LD=LD;
tr[id].LR=LR;
return true;
}
int num=1,fa=0;
int len=s.size();
while(num<len)
{
string fname=getname(s,num);
if(tr[fa].child.find(fname)==tr[fa].child.end())return false;//文件路径不存在
int id=tr[fa].child[fname];
fa=id;
if(tr[id].type)return false;//为普通文件
if(num>=len)
{
if((LD<tr[id].ld&&LD)||(LR<tr[id].lr&&LR))return false;//不满足配额要求
tr[id].LD=LD;
tr[id].LR=LR;
return true;
}
}
}
int main()
{
cin>>n;
tr[0].type=0;
tr[0].LD=tr[0].LR=tr[0].ld=tr[0].lr=0;
tr[0].father=-1;
while(n--)
{
char c;
cin>>c;
int flag=1;
if(c=='C')
{
string path;
int fsize;
cin>>path>>fsize;
flag=insert(path,fsize);
}
else if(c=='R')
{
string path;
cin>>path;
remove(path);
}
else if(c=='Q')
{
string path;
ll LD,LR;
cin>>path>>LD>>LR;
flag=config(path,LD,LR);
}
if(flag)cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
return 0;
}