元素选择器

本文讨论了在处理元素选择器时遇到的主要问题,包括使用stringstream处理空白符时的注意事项,以及在处理标签时需要考虑的不区分大小写特性。同时,提出了优化路径存在性判断的方法,通过存储父母关系并建立倒向索引来提高查询效率。对于后代选择器的匹配,文章强调了需要检查祖先并不仅限于父母,而且必须确保在树结构中。
摘要由CSDN通过智能技术生成

主要问题

  1. 读取时用stringstream处理空白符,如果用ios::sync_with_stdio(false)有问题
  2. 标签是不区分大小写的,不仅是存放时要转小写,查询时也要转小写
  3. 此问题主要是判断路径存在性,因此可以把存储方式定为只存父母
  4. 加一个倒过来的索引便于字符串查询效率
  5. 后代选择器需要匹配祖先而不只是父母(要先检查是不是在树里头,不在直接结束)

答案

#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;
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值