General idea of the topic
I / O
thinking
This problem is similar to the previous file system simulation problem, but it is not so complicated. This problem is mainly divided into two steps:
-
Building trees
First, the tree structure is established according to the input. The tree node needs to contain: label, id, level. The level can be obtained by dividing the number of '.' by 2. There is no need to record the parent-child relationship between tree nodes (i.e. no record edge), because the input of topic is based on the parent-child relationship. In the process of traversing in order, the process from parent to child can be satisfied naturally. -
Select elements
It's very simple to select a label or an id. just go through all the elements once.
For descendant selection, there is no need to distinguish whether the matching is a label or an id, as long as one can be matched. There are two ways, one is top-down, the other is bottom-up. Top down refers to the greedy matching of the first series of elements that meet the requirements of the descendant selector. For example, to find div,div,p, Then the first three lines will be matched first. When all the lines are matched successfully, the next round of matching will be decided by the level series of the next elements. For example, if the level of P element in the fourth line is less than (or equal to) the level of the last matching position, then p is also the last element in the matching selector; The div element level in the fifth row is the same as the second level of the element that last matched successfully (DIV in the second row), so the matching starts from the second in the element selector.
div ..div ....p ......p ..div
The bottom-up method refers to matching the last element first, and then matching the ancestors in the decreasing element sequence. Once all the elements in the selector are matched, a round of matching is completed. The starting position of the next round of matching is the next position equal to the last element in the element sequence.
The common point of the two methods is that they need to ensure that the elements in the selector are in a sequence of increasing or decreasing levels, which can be done by monotone stack.
code
Top down:
#include<bits/stdc++.h> using namespace std; struct ele{ string tag; string id; int level; }G[200]; string s1,s2; vector<int>ans; vector<int>tmp;//This place should be written separately, or CSP will not pass vector<string>str; int tot=0,lev=0,num=0; void tknzr(){ str.clear(); int pos=0; while(1){ pos=s2.find(" "); if(pos==string::npos){ str.push_back(s2); break; } str.push_back(s2.substr(0,pos)); s2=s2.substr(pos+1); } } void search (){ tmp.clear(); for(int i=1;i<=tot;i++){ while(!tmp.empty()&&G[i].level<=G[tmp.back()].level) num--, tmp.pop_back(); if(G[i].id==str[num]||G[i].tag==str[num]) num++,tmp.push_back(i); //If you use parameters to distinguish, you will be wrong! if(num==str.size()) ans.push_back(i),num--,tmp.pop_back(); } } int main() { int n,m; // freopen("in.txt","r",stdin); scanf("%d%d",&n,&m); getchar(); for(int i=1;i<=n;i++) { s1.clear(); getline(cin,s1); int j=0,cnt=0; string tag="",id=""; for(;s1[j]=='.';j++) if(j%2==1) cnt++; for(;s1[j]!=' '&&j<s1.size();j++) tag+= s1[j]>='A'&&s1[j]<='Z'? tolower(s1[j]):s1[j]; j++;//Skip spaces for(;j<s1.size();j++) id+=s1[j]; G[++tot].tag=tag,G[tot].id=id,G[tot].level=cnt; } for(int i=1;i<=m;i++){ s2.clear(); getline(cin,s2); ans.clear(); if(s2.find(" ")==string::npos){ if(s2[0]!='#'){ for(int s=0;s<s2.size();s++) //Change s2 to lowercase if(s2[s]>='A'&&s2[s]<='Z') s2[s]=tolower(s2[s]); for(int i=1;i<=tot;i++) if(G[i].tag==s2) ans.push_back(i); } else if(s2[0]=='#'){ for(int i=1;i<=tot;i++){ if(G[i].id==s2) ans.push_back(i); } } } else{ num=0; if(s2[0]!='#') { for(int s=0;s<s2.size();s++) //Change s2 to lowercase if(s2[s]>='A'&&s2[s]<='Z') s2[s]=tolower(s2[s]); } tknzr(); search(); } printf("%d",ans.size()); sort(ans.begin(),ans.end()); for(int i=0;i<ans.size();i++) printf(" %d",ans[i]); printf("\n"); } return 0; }
Bottom up:
#include<bits/stdc++.h> using namespace std; struct ele{ string tag; string id; int level; }G[200]; string s1,s2; vector<int>ans; vector<int>tmp;//This place should be written separately, or CSP will not pass vector<string>str; int tot=0,num=0; void tknzr(){ str.clear(); int pos=0; while(1){ pos=s2.find(" "); if(pos==string::npos){ str.push_back(s2); break; } str.push_back(s2.substr(0,pos)); s2=s2.substr(pos+1); } num = str.size(); } int main() { int n,m; // freopen("in.txt","r",stdin); scanf("%d%d",&n,&m); getchar(); for(int i=1;i<=n;i++) { getline(cin,s1); int j=0,cnt=0; string tag="",id=""; for(;s1[j]=='.';j++) if(j%2==1) cnt++; for(;s1[j]!=' '&&j<s1.size();j++) tag+= s1[j]>='A'&&s1[j]<='Z'? tolower(s1[j]):s1[j]; j++;//Skip spaces for(;j<s1.size();j++) id+=s1[j]; G[++tot].tag=tag,G[tot].id=id,G[tot].level=cnt; } for(int i=1;i<=m;i++){ getline(cin,s2); str.clear(); ans.clear(); if(s2[0]!='#'){//Change s2 to lowercase for(int s=0;s<s2.size();s++) if(s2[s]>='A'&&s2[s]<='Z') s2[s]=tolower(s2[s]);} tknzr();//participle for(int j=n;j>=1;j--) { num=str.size()-1; if(G[j].tag==str[num]||G[j].id==str[num]) //Equal to the last token { tmp.clear(); tmp.push_back(j);//It's a high level ancestor while(--num>=0) //Consider the next token whose lev must be in a decreasing sequence { int u=0; for(int k=tmp.back();k>=1;k--) { if(G[k].level<G[tmp.back()].level) { tmp.push_back(k); if(G[k].tag==str[num]||G[k].id==str[num]){ u = k; break; } } } if(G[u].tag!=str[num]&&G[u].id!=str[num]) break; } if(num<0) ans.push_back(j); } } printf("%d",ans.size()); sort(ans.begin(),ans.end()); for(int i=0;i<ans.size();i++) printf(" %d",ans[i]); printf("\n"); } return 0; }