题目
思路
构建结构化文档:
使用结构体数组来记录结构化文档,结构体中包含label,id,自己的层次和父节点,父节点记录其父节点所在行,可将其作为索引直接找到父节点。
对结构化文档,每次读取一行,读取前面的“ . ”的数量,点的数量除以2当作其层次。对于第一行没有父节点且其前面没有点需要做特殊处理。
从vector最后的位置向前遍历,找到第一个层次数小1的即为父节点,记录下来。
通过前面是否有空格和“#”来区分是否为id,将label和id储存到vector中
查找:
若为单一的label或者是id查找,则只需要从头到尾遍历一遍就可以。如果符合,则存放到result中,最后输出总数量和每一个符合的行号。
若为多查找,则从尾反向遍历,如果找到符合得了,则根据该节点记录得父节点得行号直接跳跃。
代码
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
int n,m;
struct html{
int level,father; //父节点指向父亲所在的行
string label,id;
};
vector<html> Html; //存放每行的记录
vector<int> result; //存储要输出的结果
char change(char t){
if(t>=97) t-=32;
return t;
}
int main(){
cin>>n>>m;
getchar(); //处理掉回车
while(n--){
int fa,level; //分别记录父节点和行数
string s,label,id;
getline(cin,s);
int p = 0; //记录点数
while(s[p] == '.') p++;
level = p / 2; //层级数
if(p == 0 || !Html.size()){
fa = -1 ; //没有父节点或者是第一个
}else{
for(int i = Html.size() - 1;i >= 0;i--){
if(Html[i].level == level - 1){
//找到其父节点的层数
fa = i;
break;
}
}
}
int r = false;
while(p < s.size()){
//找出后面的label和id
if(s[p] == ' '){
p++;
continue;
}
if(s[p] == '#'){
//有描述信息id
r = true;
id += s[p];
p++;
continue;
}
if(r) id += s[p]; //描述信息
else label += change(s[p]); //全部转化为小写
p++;
}
Html.push_back({
level,fa,label,id});
}
while(m--){
//读取查找的信息
string s;
getline(cin,s);
int p = 0;
while(p != s.size() - 1 && s[p] != ' ') p++;
if(p == s.size() - 1){
//单一选择器
if(s[0] == '#'){
//id特征查找
for(int i = 0;i < Html.size();i++){
if(s == Html[i].id) result.push_back(i+1);
}
}else{
//label,不区分大小写
for(int i = 0;i < s.size();i++){
s[i] = change(s[i]);
}
for(int i = 0;i < Html.size();i++){
if(s == Html[i].label) result.push_back(i+1); //找到
}
}
cout<<result.size()<<" ";
for(int i = 0;i < result.size();i++) cout<<result[i]<<" ";
}else{
//多个查找
int j = 0;
vector<string> v;
p = 0;
bool flag = true;
while(p < s.size()){
if(s[p] == '#') flag = false;
if(s[p] == ' '){
flag = true;
v.push_back(s.substr(j,p-j));
j = p + 1;
}
if(flag) s[p] = change(s[p]); //id不在意大小写,故全转换为小写
p++;
}
v.push_back(s.substr(j,p-j));
for(int i = Html.size() - 1;i > 0;i--){
//父节点在上面
int q = v.size() - 1; //要查找的文件的个数
if(v[q] != Html[i].label && v[q] != Html[i].id) continue;
p = Html[i].father; //找到,则直接去找其父节点
q--;
while(q >= 0 && p >= 0){
if(Html[p].label == v[q] || Html[p].id == v[q]) q--;
p = Html[p].father;
}
if(q == -1) result.push_back(i+1); //说明找到
}
cout<<result.size()<<" ";
for(int i = result.size()-1;i >= 0;i--) cout<<result[i]<<" ";
}
cout<<endl;
result.clear();
}
return 0;
}