多级的后代选择器在匹配时,可以采用贪心的策略:除最后一级外,前面的部分都可以尽量匹配层级小的元素。
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
const int maxn = 1005;
struct node{
string name, id;
} tree[maxn]; //树形结构
vector<int> q[maxn]; //层叠表
int point[maxn]; //存点的个数
stack<int> s; //辅助建树
int n, m;
string ss[maxn]; //保存选择器单词
int num,cnt; //层数
int ans[maxn]; //答案
void dfs_name(int x, int y);
void dfs_id(int x,int y) //id选择器
{
if(tree[x].id==ss[y]) //匹配成功
y++;
if(y>num) ans[cnt++]=x,y=num; //匹配完最后一个,要继续匹配最后一个
for(int i=0;i<q[x].size();i++)
if(ss[y][0]=='#') dfs_id(q[x][i],y);
else dfs_name(q[x][i],y);
}
void dfs_name(int x,int y) //标签选择器
{
if(tree[x].name==ss[y]) //匹配成功
y++;
if(y>num) ans[cnt++]=x,y=num; //匹配完最后一个,记录答案,接下来还是重新匹配最后一个
for(int i=0;i<q[x].size();i++)
if(ss[y][0]=='#') dfs_id(q[x][i],y);
else dfs_name(q[x][i],y);
}
int main()
{
cin >> n >> m;
getchar();
tree[0].name = "";
tree[0].id = "";
for (int i = 1; i <= n;i++) //数据处理
{
string st;
string name, id;
getline(cin, st); //读入一整行内容
int len = st.size();
bool flag = false; //有无id标记
for (int j = 0; j < len;j++)
{
if(st[j]=='.') //point
{
point[i]++;
}
else if(st[j]==' ') //有id
{
flag = true;
while(j+1<len&&st[j+1]==' ')//跳过空格
j++;
}
else
{
if(!flag)
name += tolower(st[j]); //name不分大小写
else
id += st[j];
}
}
tree[i].name = name;
tree[i].id = id;
while(!s.empty()&&point[s.top()]>=point[i]) //找前面比自己点数小的第一行
{
s.pop();
}
if(!s.empty())
q[s.top()].push_back(i);
else
q[0].push_back(i);
s.push(i);
}
while(m--) //处理待查询的选择器
{
string s;
getline(cin, s);
num = 0; //层数清零
ss[0] = ""; //总根
int len = s.size();
for (int i = 0; i < len;i++) //处理数据
{
if(s[i]==' ')
{
if(ss[num]!="")
num++,ss[num]="";
while(i+1<len&&s[i+1]==' ') i++;
}
else ss[num]+=s[i];
}
if(ss[num]=="")
num--;
for(int i=0;i<=num;i++)
if(ss[i][0]!='#') //将标签化为小写
for(int j=0;j<ss[i].length();j++)
ss[i][j]=tolower(ss[i][j]);
cnt=0;
if(num==0)
{
if(ss[0][0]=='#')
{
for(int i=1;i<=n;i++)
if(tree[i].id==ss[0]) ans[cnt++]=i;
}
else
{
for(int i=1;i<=n;i++)
if(tree[i].name==ss[0]) ans[cnt++]=i;
}
}
else //后代选择器
{
if(ss[0][0]=='#')
{
dfs_id(0,0);
}
else
{
dfs_name(0,0);
}
}
sort(ans,ans+cnt);
printf("%d",cnt);
for(int i=0;i<cnt;i++)
printf(" %d",ans[i]);
printf("\n");
}
}