csp18年09-3T元素选择器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

解题思路

对于这个题,难点在于处理后代选择器。首先我们可以采用一个结构体在存储每一层的内容,记录该层的标签,id和它是哪一级,由于标签对大小写是不敏感的,所以为了方便处理,我们将所有的标签都转换为小写。在处理每一条指令的时候,我们将指令中的每一个部分都单独取出来存到一个vector中,只有后代选择器才会有多个组成部分。所以对于后代选择器,我们首先要找到最后一部分所在的层,可以使用一个for循环找到,然后去找其父亲或祖父等。对于找父亲和祖父,我们可以维护一个开始的层和开始的级,当开始初始化为儿子所在层和级,然后找到其父亲后进行相应的更新,然后逐渐进行此过程,最后在所有的祖先都找完之后,退出循环。

代码

#include<iostream>
#include<string>
#include<vector>
#include<cstring>
using namespace std;
struct ceng{//存储每一层
	string la,id;//标签和id
	int lev;//所在级
};
ceng ce[110];
bool sea(int &le,int &st,string str)
{//查找父辈
	for(int i=st;i>=1;i--)
	{
		if(ce[i].lev<le)
		{//如果找到比当前级更小的
			le=ce[i].lev;
			st=i;//更新
			if(str==ce[i].la||str==ce[i].id)//如果正好等于要找的父辈
				return true;//返回
		}
	}
	return false;
}
int main()
{
	int n,m;
	cin>>n>>m;
	getchar();
	string str;
	for(int i=1;i<=n;i++)
	{
		getline(cin,str);
		int f1=-1,f2=-1,ll=0;
		for(int j=0;j<str.size();j++)
		{
			if(str[j]=='.')
				ll++;	//计算级数
			else if(f1==-1&&str[j]!='#')
				f1=j;//标签
			else if(str[j]=='#')
				f2=j;//id
		}	
		ce[i].lev=ll;
		if(f2==-1)//没有id
		{
			ce[i].la=str.substr(f1);
			ce[i].id="";
		}else{//有id
			ce[i].la=str.substr(f1,f2-f1-1);
			ce[i].id=str.substr(f2);
		}
		for(int k=0;k<ce[i].la.size();k++)
		{//将标签转换为小写
			if(ce[i].la[k]>='A'&&ce[i].la[k]<='Z')
				ce[i].la[k]+=32;
		}
	}
	for(int i=0;i<m;i++)
	{
		char co[100];
		gets(co);
		vector<string> cc;
		vector<int> ans;	
		char *te=strtok(co," ");
		while(te)//取出该查找的每一个部分,存到cc中
		{
			cc.push_back(te);
			te=strtok(NULL," ");
		}
		for(int j=0;j<cc.size();j++)
		{
			if(cc[j][0]!='#')
			{//如果该指令为标签,则转为小写
				for(int k=0;k<cc[j].size();k++)
				{
					if(cc[j][k]>='A'&&cc[j][k]<='Z')
						cc[j][k]+=32;
				}
			}
		}
		for(int j=1;j<=n;j++)
		{
			if(cc[cc.size()-1]==ce[j].la||cc[cc.size()-1]==ce[j].id)
			{//找到最后一部分所对应的层,然后找父辈
				int ss=j,level=ce[j].lev,k;
				for(k=cc.size()-2;k>=0;k--)
				{
					if(!sea(level,ss,cc[k]))
						break;
				}
				if(k<0)//所以父辈都找到
					ans.push_back(j);
			}
		}
		cout<<ans.size();
		for(int j=0;j<ans.size();j++)
			cout<<" "<<ans[j];
		cout<<endl;
	}	
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值