题意:
思路:
1.关于选择器先明确一下:
选择器有三种情况,有标签选择器,id选择器,两者复合的后代选择器(前面两者易于理解,第三个选择器比较复杂)
理解一下后代选择器:格式为A B,其中A和B均为标签选择器或id选择器(二者)
2.具体思路:
(1)有层级关系,联想到树,便于对上级进行查询,定义结构体element,记录需要的各种信息:包括查询内容,层级,行号
(2)将element内容存放在数组中,在前两个选择器的操作中,直接遍历数组找到符合的结果,记录行号;在后代选择其中,先遍历确定最后一个查询项目是否出现,如果出现了,再向前回溯找它的上一级是否满足,若上级(还有上上级之类,与输入有关)满足要求,则记录之前最后一个查询项目的行号
3.字符串的处理问题:
之前总结了一下,这里就不写了。
4.一些小细节:
标签大小写不敏感,id敏感;这里我将字符串全部转换为小写字母
代码:
#include<bits/stdc++.h>
using namespace std;
struct element
{
string text; //内容
int lever,row; //层 行数
}q[210];
int cnt;
string Lower(string s) //字符串转换为小写
{
for(int i = 0; i < s.size(); i++)
s[i] = tolower(s[i]);
return s;
}
void insert(string s, int i)
{
string name, id;
q[cnt].row = i;
int tlevel = 0;
if(s.find('.') != string::npos)
tlevel = (int)s.find_last_of('.') + 1; //统计.的个数
q[cnt].lever = tlevel / 2;
if(s.find(' ') != string::npos) //有id
{
int pos = (int)s.find(' ');
id = s.substr(pos + 1);
name = s.substr(tlevel, pos - tlevel);
}
else name = s.substr(tlevel); //没有id
q[cnt].text = Lower(name);
if(!id.empty()){
q[++cnt].row = i;q[cnt].text = id;q[cnt].lever = tlevel / 2;
}
cnt++;
}
int main()
{
int n, m , be;
string s;
cin >> n >> m; cin.ignore();
for(int i = 1; i <= n; i++){
getline(cin, s);
insert(s, i);
}
for(int i = 0; i < m; i++)
{
getline(cin, s);
vector<string> v;
istringstream ss(s);
while(ss >> s) v.push_back(s[0] == '#' ? s : Lower(s)); //标签,转换小写
vector<int> ans;
if(v.size() == 1) //选择器一项
{
for(int i = 0; i < cnt; i++)
if(v[0] == q[i].text)
ans.push_back(q[i].row);
}
else if(v.size() > 1) //选择器多项
{
for(int i = 0; i < cnt; i++) //寻找最后一个
if(v.back() == q[i].text) //找到最后一项
{
int r = 0, m = q[i].lever;
be = i - 1;
for(int a = v.size() - 2; a >= 0; a--) //从最后一项往前
for(int b = be; b >= 0; b--)
if(q[b].text == v[a] && q[b].lever < m)
{
r++;
m = q[b].lever; //更新层级
be = b - 1;
break;
}
if(r == v.size() - 1) ans.push_back(q[i].row);
}
}
cout << ans.size();
for(auto &x : ans) cout << " " << x;
cout << endl;
}
return 0;
}