问题描述
思路
本题的关键点是元素和id的存储和查询,由于查询有两种格式的数据,且要求元素大小写不敏感,所以要设计n*2数据存储每行数据的元素和id,且存储和查询的过程中用change把元素转化成小写。
由于元素查询有多级选择,在
n
2
n^2
n2的复杂度内考虑遍历所有行的元素或id,一旦等于后代选择器要求的最后一个元素,自底向上查看他的祖先是否含有选择器中的祖先序列,有则当前行元素或id满足,加入答案。由于我们只关心祖先元素,所以考虑用数组p来存储每一个祖先的行号。
那么如何处理结构化文档呢,可以采用栈的结构,对于新加入的元素,先弹出层级小于等于它的,保证栈中只含有它的祖先,此时栈顶元素就是它的父亲,更新p数组,可以保证已经弹出的元素p已经更新过。
有一个坑,不同元素的id值不同,注意审题。
模拟题为了优化代码,可以考虑使用各种stl或者其他优化。本题对于每一行的数据如何处理可以采用stringstream来分离元素和id(id可以为空),如何删除’…'可以采用string的substr或者char[]的strncpy(这个要提前清零)
代码
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<map>
#include<stack>
#include<vector>
#include<sstream>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define mem(a,s) memset(a,s,sizeof(a))
typedef long long LL;
const int N = 100 + 5;
string s[N][2];
int p[N],n,m;
stack<pair<int, int> > st;
string change(string x){
if(x[0]!='#')
transform(x.begin(),x.end(),x.begin(),::tolower);
return x;
}
bool find(int i,vector<string>& vec){
int len = vec.size()-1;
if(len==0)return true;
len--;i = p[i];
while(i){
if((vec[len][0]=='#'&&vec[len]==s[i][1])
||(vec[len][0]!='#'&&vec[len]==s[i][0]))
len--;
if(len==-1)
return true;
i = p[i];
}
return false;
}
int main(){
// freopen("in.txt","r",stdin);
cin>>n>>m;
getchar();
rep(i,1,n){
char y[90],x[90];
gets(y);
int j = 0;
while(y[j]=='.')j++;
mem(x, 0);
strncpy(x, y + j, strlen(y) - j);
stringstream ss(x);
ss >> s[i][0] >> s[i][1];
s[i][0] = change(s[i][0]);
while(!st.empty()&&st.top().second>=j)
st.pop();
if(!st.empty())
p[i] = st.top().first;
st.push({i, j});
}
vector<string> vec;
vector<int> ans;
while(m--){
char x[90];
vec.clear();
ans.clear();
gets(x);
stringstream ss(x);
string str;
while(ss>>str)
vec.push_back(change(str));
int siz = vec.size();
int idx = 0;
if(vec[siz-1][0]=='#')
idx = 1;
rep(i, 1, n) if (s[i][idx] == vec[siz - 1] && find(i, vec))
ans.push_back(i);
cout << ans.size();
for(auto it:ans)
cout << ' ' << it;
cout << endl;
}
return 0;
}