解题思路
对于这个题,难点在于处理后代选择器。首先我们可以采用一个结构体在存储每一层的内容,记录该层的标签,id和它是哪一级,由于标签对大小写是不敏感的,所以为了方便处理,我们将所有的标签都转换为小写。在处理每一条指令的时候,我们将指令中的每一个部分都单独取出来存到一个vector中,只有后代选择器才会有多个组成部分。所以对于后代选择器,我们首先要找到最后一部分所在的层,可以使用一个for循环找到,然后去找其父亲或祖父等。对于找父亲和祖父,我们可以维护一个开始的层和开始的级,当开始初始化为儿子所在层和级,然后找到其父亲后进行相应的更新,然后逐渐进行此过程,最后在所有的祖先都找完之后,退出循环。
代码
#include<iostream>
#include<string>
#include<vector>
#include<cstring>
using namespace std;
struct ceng{//存储每一层
string la,id;//标签和id
int lev;//所在级
};
ceng ce[110];
bool sea(int &le,int &st,string str)
{//查找父辈
for(int i=st;i>=1;i--)
{
if(ce[i].lev<le)
{//如果找到比当前级更小的
le=ce[i].lev;
st=i;//更新
if(str==ce[i].la||str==ce[i].id)//如果正好等于要找的父辈
return true;//返回
}
}
return false;
}
int main()
{
int n,m;
cin>>n>>m;
getchar();
string str;
for(int i=1;i<=n;i++)
{
getline(cin,str);
int f1=-1,f2=-1,ll=0;
for(int j=0;j<str.size();j++)
{
if(str[j]=='.')
ll++; //计算级数
else if(f1==-1&&str[j]!='#')
f1=j;//标签
else if(str[j]=='#')
f2=j;//id
}
ce[i].lev=ll;
if(f2==-1)//没有id
{
ce[i].la=str.substr(f1);
ce[i].id="";
}else{//有id
ce[i].la=str.substr(f1,f2-f1-1);
ce[i].id=str.substr(f2);
}
for(int k=0;k<ce[i].la.size();k++)
{//将标签转换为小写
if(ce[i].la[k]>='A'&&ce[i].la[k]<='Z')
ce[i].la[k]+=32;
}
}
for(int i=0;i<m;i++)
{
char co[100];
gets(co);
vector<string> cc;
vector<int> ans;
char *te=strtok(co," ");
while(te)//取出该查找的每一个部分,存到cc中
{
cc.push_back(te);
te=strtok(NULL," ");
}
for(int j=0;j<cc.size();j++)
{
if(cc[j][0]!='#')
{//如果该指令为标签,则转为小写
for(int k=0;k<cc[j].size();k++)
{
if(cc[j][k]>='A'&&cc[j][k]<='Z')
cc[j][k]+=32;
}
}
}
for(int j=1;j<=n;j++)
{
if(cc[cc.size()-1]==ce[j].la||cc[cc.size()-1]==ce[j].id)
{//找到最后一部分所对应的层,然后找父辈
int ss=j,level=ce[j].lev,k;
for(k=cc.size()-2;k>=0;k--)
{
if(!sea(level,ss,cc[k]))
break;
}
if(k<0)//所以父辈都找到
ans.push_back(j);
}
}
cout<<ans.size();
for(int j=0;j<ans.size();j++)
cout<<" "<<ans[j];
cout<<endl;
}
return 0;
}