一、思路:

1、将结构化文档的每一行处理成一个节点(可定义一个结构体,成员包含标签tag、属性id、层级level、祖先所在行数father)。

2、然后整个结构化文档就成了一个树形结构,可从任一节点轻松访问到祖先节点。

3、从1到n行遍历文档,将后代选择器从后往前依次与第i行所在节点及其祖先节点匹配。

4、【提示】多级的后代选择器在匹配时,可以采用贪心的策略:除最后一级外,前面部分都可以尽量匹配层级小的元素(在树中较深的节点)。

  一开始没懂提示在说啥,后来做出来只有80分,百度了一下才知道:祖先的祖先仍是祖先。

  例如 div p 这个命令,如果p是第10级,div是第1级,这个p也能被选中。

5、注意:tag对大小写不敏感,id属性对大小写敏感。

二、代码:

对C++STL的string类型和stringstream流不熟悉,因此虽是C++代码,但有点偏C的风格。

  1. #include<cstdio>
  2. #include<vector>
  3. #include<stack>
  4. #include<cstring>
  5. #include<iostream>
  6. using namespace std;
  7. const int N=;
  8. const int M=;
  9. struct node
  10. {
  11. char tag[M],id[M];
  12. int level,father;
  13. };
  14. node text[N];
  15. bool equal(char*str1,char*str2)
  16. {
  17. while(*str1||*str2){
  18. if(*str1>=''&&*str1<=''){
  19. if(*str1!=*str2)return false;
  20. }
  21. else{
  22. if(*str1>'Z')*str1-=;
  23. if(*str2>'Z')*str2-=;
  24. if(*str1!=*str2)return false;
  25. }
  26. str1++;str2++;
  27. }
  28. return true;
  29. }
  30. int main()
  31. {
  32. //freopen("in.txt","r",stdin);
  33. int n,m;
  34. stack<pair<int,int> >fa;
  35. fa.push(make_pair(-,-));
  36. scanf("%d%d",&n,&m);
  37. getchar();
  38. for(int i=;i<=n;i++){
  39. char str[M];
  40. //gets(str);
  41. fgets(str,M,stdin);
  42. //cout<<i<<' '<<str<<endl;
  43. int j=;
  44. while(str[j]=='.')j++;
  45. text[i].level=j/;
  46. pair<int,int>par=fa.top();
  47. //cout<<par.first<<' '<<par.second<<endl;
  48. while(par.second>=text[i].level){
  49. fa.pop();par=fa.top();
  50. //cout<<par.first<<' '<<par.second<<endl;
  51. }
  52. //cout<<endl;
  53. text[i].father=par.first;
  54. if(sscanf(str+j,"%s%s",text[i].tag,text[i].id)==)text[i].id[]=;
  55. fa.push(make_pair(i,text[i].level));
  56. }
  57. /*
  58. for(int i=1;i<=n;i++){
  59. node&t=text[i];
  60. cout<<t.father<<' '<<t.level<<' '<<t.tag<<' '<<t.id<<endl;
  61. }
  62. */
  63. //getchar();
  64. while(m--){
  65. int i=;
  66. vector<int>ans;
  67. char c,order[M],temp[M];
  68. while((c=getchar())!=EOF&&c!='\n'){
  69. order[i++]=c;
  70. }
  71. order[i]=;
  72. int len=i;
  73. for(int k=;k<=n;k++){
  74. int now=k,flag=;
  75. i=len;
  76. while(){
  77. while(i>=&&order[i]!=' ')i--;
  78. sscanf(order+i+,"%s",temp);
  79. if(temp[]=='#'){
  80. if(strcmp(temp,text[now].id)==){
  81. flag=;
  82. if(i==-)ans.push_back(k);
  83. i--;
  84. }
  85. else if(flag==)i=-;
  86. else i++;
  87. }
  88. else {
  89. if(equal(temp,text[now].tag)){
  90. flag=;
  91. if(i==-)ans.push_back(k);
  92. i--;
  93. }
  94. else if(flag==)i=-;
  95. else i++;
  96. }
  97. now=text[now].father;
  98. if(now==-)i=-;
  99. if(i<)break;
  100. }
  101. }
  102. printf("%d",ans.size());
  103. for(i=;i<ans.size();i++){
  104. printf(" %d",ans[i]);
  105. }
  106. printf("\n");
  107. }
  108. return ;
  109. }

ccf 201809-3 元素选择器的更多相关文章

  1. CCF(元素选择器:50分):字符串+模拟

    元素选择器 201809-3 这里我只考虑了没有后代选择器的情况 #include<iostream> #include<cstdio> #include<cstring ...

  2. 深入学习jQuery选择器系列第八篇——过滤选择器之伪子元素选择器

    × 目录 [1]通用形式 [2]反向形式 [3]首尾元素 [4]唯一元素 前面的话 本文是子元素选择器的续篇,主要介绍关于nth-of-type()选择器的内容.该部分内容并非没有出现在<锋利的 ...

  3. 深入学习jQuery选择器系列第二篇——过滤选择器之子元素选择器

    × 目录 [1]通用形式 [2]反向形式 [3]首尾元素 [4]唯一元素 前面的话 在上一篇中已经介绍过基础选择器和层级选择器,本文开始介绍过滤选择器.过滤选择器是jQuery选择器中最为庞大也是最为 ...

  4. CSS之元素选择器

    1.后代元素选择器 div p 以空格分隔,表示div的所有后代p元素 2.子元素选择器 div > p 以大于号分隔,表示div的直接子元素 3.相邻兄弟选择器 div  + p 选择紧接在d ...

  5. css伪类选择器及伪元素选择器

    1.类选择器 在css中可以使用类选择器把相同的元素定义成不同的样式.比如: 结果如下: 标题背景未变 2.伪类选择器 类选择器和伪类选择器的区别在于,类选择器我们定义的,而伪类选择器是CSS中已经定 ...

  6. CSS中模拟父元素选择器

    很多情况下,我们需要找到父元素,但可惜的是css中并没有这样的一个选择器. 至于原因可以看张鑫旭的如何在CSS中实现父选择器效果这篇文章. 简单来说这个实现并不是真正的父元素选择器,只是利用其它思路来 ...

  7. jquery子元素选择器

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. css伪元素选择器

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  9. CSS_03_04_CSS伪元素选择器

    第01步:编写css代码:wei.css @charset "utf-8"; /* 伪元素选择器 :状态 效果顺序:L V H A */ a:link.lin_01{/*超链接,未 ...

  10. CSS 子元素选择器与后代选择器区别实例讲解

    css子元素选择器和后代选择器在功能描述上非常相同,但是他们其实是有区别的,本文章通过两个简单的实例向大家介绍子元素选择器与后代选择器的区别,需要的朋友可以参考一下. 首先我们来了解一下子元素选择器与 ...

随机推荐

  1. [Codeforces 163D]Large Refrigerator (DFS+剪枝)

    [Codeforces 163D]Large Refrigerator (DFS+剪枝) 题面 已知一个长方体的体积为V,三边长a,b,c均为正整数,求长方体的最小表面积S V以质因数分解的形式给出 ...

  2. go 学习之bufio

    bufio模块通过对io模块的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销.实际上在bufio各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行.当发起一次读写操作时 ...

  3. NEO4J -模糊查询

    模糊查询 match(emp) where emp.name =~'.*haha.*' return emp 现有节点创建关系 MATCH (cust:Customer),(cc:CreditCard ...

  4. Zookeeper之启动常见错误及解决方法

    Zookeeper启动后,有时候没有真正的启动,那我们如何查找错误呢,就可以查看zookeeper目录下面的zookeeper.out文件,就可以查看到错误了.zookeeper.out文件比较的重要 ...

  5. node-sass 安装失败解决方法

    使用淘宝镜像源 npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/ npm install node-s ...

  6. Python之文件路径名的操作

    使用 os.path 模块中的函数来操作路径名 import os # 获取当前文件路径 path=os.path.abspath(__file__) # 获取绝对路径 /home/zzy/Pycha ...

  7. 无法删除VMware旧版本,请与技术小组联系

    问题:把文件夹清理了n遍,却无法重装VMware,报错如标题. 原因:相关注册表没删完. 解决办法: - 1.创建一个.txt文本 - 2.将下面的内容复制到.txt文本中: echo off cls ...

  8. 廖雪峰Python电子书总结

    函数 1.注意:函数的默认参数必须指向不可变对象 未修改前: def add_end(L=[]): L.append('END') return L 存在的问题:如果连续调用多次,会出现多个 'END ...

  9. proc - 进程信息伪文件系统

    描述 /proc 是一个伪文件系统, 被用作内核数据结构的接口, 而不仅仅是解释说明 /dev/kmem. /proc里的大多数文件都是只读的, 但也可以通过写一些文件来改变内核变量. 下面对整个 / ...

  10. 数据库系统实现 第一章 DBMS实现概述

    DBMS提供的能力 1)持久存储 DBMS在灵活性方面比文件系统要好,同时支持对非常大量数据的存储 2)编程接口 3)事务管理 DBMS支持对数据的并发存取,即多个不同的进程(称作事物)同时存取操作, ...