Loading

201809-3 元素选择器

时间限制:1.0s
内存限制:256MB
题目描述:
image

分析

依据题意,我们需要对选择器进行匹配,找出全部满足的位置:

  1. 单独lable的匹配
  2. 单独id的匹配
  3. 嵌套lable或id的匹配

其中1、2两个匹配比较好容易,遍历一遍结构化文档(即输入的n行)即可,对于第3个匹配,需要满足以下几点:

  1. 祖先元素必须在匹配元素之前,即下面示例只有第一个div是p祖先元素

    div
    ..p
    div
    
  2. 祖先元素必须和匹配元素在同一个树结构内,即下面示例只有第二个div是p祖先元素

    div
    ..#id
    div
    ....p
    
  3. 祖先元素的缩进必须小于后一个祖先元素or匹配元素

解法

  1. 选择合适的结构存储结构化文档(n行输入)

    经过分析我们可以知道,输入的每一行有以下几种可能,并且lable和id不会重名

    • 单个lable
    • 单个id
    • lable id

    因此选择以下数据结构存储输入:

    struct Node
    {
        string lable, id;
        int cnt;
    }a[N];
    
  2. 读入结构化文档

    需要注意的是lable不区分大小写,一般这种情况我们将其转换为小写存储便于操作。

    for(int i = 0; i < n; i++)
    {
        int cnt = 0, flag = 0;
        string lable = "", id = "";
        while((c = getchar()) != '\n')
        {
            if(c == '.')
            {
                cnt++;
                continue;
            }
            if(c == ' ')
            {
                flag = 1;
                continue;
            }
            if(flag == 1)
            {
                if(c != '\n')
                    id += c;
                else
                    flag = 0;
            }
            else
                lable += c;
        }
        //lable变小写存储
        transform(lable.begin(),lable.end(),lable.begin(),::tolower);
        a[i].cnt = cnt;
        a[i].id = id;
        a[i].lable = lable;
    }
    
  3. 读入选择器

    同样我们需要将lable的选择器转换成小写存储。选择器有可能是' '分割的多级,因此用vector<string>存储。

    //读入一个选择器
    string s = "";//注意初始化为空便于+=操作
    vector<string> v;
    vector<int> ans;
    while((c = getchar()) != '\n')
    {
        if(c == ' ')
        {
            if(s[0] != '#')
            {
                transform(s.begin(),s.end(),s.begin(),::tolower);
            }
            v.push_back(s);
            s = "";
        }
        else
        {
            s += c;
        }
    }
    if(s[0] != '#')
    {
        transform(s.begin(),s.end(),s.begin(),::tolower);
    }
    v.push_back(s);
    
  4. 选择元素
    首先说明外面的大循环,对于n行中每行,都判断是否能被选择器中最后一项选择,如果能并且祖先也满足(selector返回true),则成功选择,将其加入结果向量。
    注意由于lable和id不重名,故在判断是否存在于n行中的时候无需区分,直接同时和lable和id对比即可。

    int len = v.size();
    //对每个存在于文档中的末级元素,若所有祖先满足则成功select
    for(int j = 0; j < n; j++)
    {
        if(a[j].id == v[len-1] || a[j].lable == v[len-1])
        {
            int end = j, cnt = a[j].cnt, k;
            for(k = len-2; k >= 0; k--)//判断祖先是否满足
            {
                if(!selector(0,end,v[k],cnt))break;
            }
            if(k < 0)
                ans.push_back(j+1);
        }
    }
    

    祖先的判断函数:

    bool selector(int start, int& end, string s, int& cnt)
    {
        for(int i = end-1; i >= 0; i--)
        {
            if(a[i].cnt < cnt)
            {
                cnt = a[i].cnt;//只有在同一棵树内才符合祖先定义
                end = i;
                if(a[i].lable == s || a[i].id == s)return true;
            }
        }
        return false;
    }
    

完整代码

posted @ 2021-08-03 19:32  Imane219  阅读(46)  评论(0)    收藏  举报
hi