主要问题
- 读取时用stringstream处理空白符,如果用ios::sync_with_stdio(false)有问题
- 标签是不区分大小写的,不仅是存放时要转小写,查询时也要转小写
- 此问题主要是判断路径存在性,因此可以把存储方式定为只存父母
- 加一个倒过来的索引便于字符串查询效率
- 后代选择器需要匹配祖先而不只是父母(要先检查是不是在树里头,不在直接结束)
答案
#include <bits/stdc++.h>
using namespace std;
int level(string &str){
size_t p = str.rfind('.');
if(p == string::npos)
return 0;
else
{
str = str.substr(p+1);
return (p+1)/2;
}
}
struct page{
int parent = 0;
int level = -1;
string tag = "";
string id = "";
};
unordered_map<string, vector<int>> quick_index;
unordered_map<int,page> tree;
int main(){
int m , n;
cin >> m >> n;getchar();
string line,s;
int last_id = -1;
for(int i = 1; i <= m ; i++){
page cur;
getline(cin,line);
stringstream ss(line);
ss >> s;
cur.level = level(s);
while(cur.level <= tree[last_id].level )
last_id = tree[last_id].parent;
cur.parent = last_id;
tree[i] = cur;
transform(s.begin(),s.end(),s.begin(),::tolower);
quick_index[s].push_back(i);
tree[i].tag = s;
if(ss >> s)
{
quick_index[s].push_back(i);
tree[i].id = s;
}
last_id = i;
}
for(int i = 0 ; i < n ;i++){
vector<string> tmp;
getline(cin,line);
stringstream ss(line);
ss >> s;
if(s.find('#') == string::npos)
transform(s.begin(),s.end(),s.begin(),::tolower);
if(!quick_index.count(s)) {
cout << 0 <<endl;
continue;
}
tmp.push_back(s);
while(ss >> s){
if(s.find('#') == string::npos)
transform(s.begin(),s.end(),s.begin(),::tolower);
tmp.push_back(s);
}
vector<int> output;
int last = tmp.size()-1;
for(auto &it : quick_index[tmp[last]]){
int j = tmp.size()-1 , cur = it;
while(j > 0){
cur = tree[cur].parent;
if(!quick_index.count(tmp[j-1]))
break;
while(tmp[j-1] != tree[cur].tag && tmp[j-1] != tree[cur].id
&& cur != -1)
cur = tree[cur].parent;
if(cur == -1)
break;
j--;
}
if(j == 0)
output.push_back(it);
}
cout << output.size();
for(auto &it:output){
cout <<" "<<it;
}
cout<<endl;
}
}