CSP认证202303-3:LDAP (超详细题解)

题目传送门

解题思路

最后要求输出符合条件的用户 DN 的集合, (作为一名STL战士) ,可以考虑维护以属性名和属性值为索引, 对应值为符合条件的用户的set 的一个map

属性名 -> 属性值 -> {用户1,用户2…}

unordered_map<int,unordered_map<int,set<int>>> attrName_attrVal_users;

操作分为原子操作和逻辑操作, 只需要判断字符串的首字符即可区分两种操作

原子操作

原子操作分为匹配和剔除, 匹配满足条件(属性名为相应属性值)的用户集合可以直接从刚才的map里找到, 作为答案, 而剔除时需要注意, 只有当用户该属性有值且不为指定值时才能作为答案, 所以为了便于判断用户指定属性是否有值(不为N/A), 可以维护一个以属性名为索引, 值为相应用户集合的map

属性名 -> {用户1,用户2…}

unordered_map<int, set<int>> attrName_users;
逻辑组合

逻辑操作主要是符合条件的用户集合的交和并, 以及逻辑操作的嵌套, 这里用两个set ans1ans2 来暂存符合条件的用户

交: 将两个集合插入另一个集合即可
ans.insert(ans1.begin(), ans1.end());
ans.insert(ans2.begin(), ans2.end());
并: 枚举一个集合, 判断每个元素在不在另一个集合中即可
for(auto it : ans1) {
	if(ans2.count(it)) {
		ans.insert(it);
	}
}
嵌套: 括号匹配

对于一个逻辑操作表达式的前后两个部分, 我们发现他们无论怎么嵌套, 每个部分的括号一定是匹配的, 可以维护一个括号栈, 遍历字符串直到括号栈空, 此时字符串的位置 (本文为p) 为前后两个部分的分界位置

然后递归调用即可

在这里插入图片描述

完整代码

#include<bits/stdc++.h>
using namespace std;

int n;
unordered_map<int,unordered_map<int,set<int>>> attrName_attrVal_users; // 存储 属性名-属性值-用户DN 
unordered_map<int, set<int>> attrName_users; // 存储该属性不为NA的用户DN set 

int getNum(string exp) {// 字符串转整形 
	int ans = 0;
	for(int i = 0; i < exp.size(); i++) {
		ans *= 10;
		ans += (exp[i] - '0');
	}
	return ans;
}

set<int> AtomOP(string exp) {// 原子操作 
	int p = 0;set<int> ans;
	while(exp[p] != ':' && exp[p] != '~') p++;
	int a = getNum(exp.substr(0,p));
	int b = getNum(exp.substr(p+1, exp.size()));
	if(exp[p] == ':') {
		ans.insert(attrName_attrVal_users[a][b].begin(), attrName_attrVal_users[a][b].end());
	}
	else {
		ans.insert(attrName_users[a].begin(), attrName_users[a].end());
		set<int> dead;
		for(auto it : attrName_attrVal_users[a][b]) {
			if(ans.count(it)) {
				dead.insert(it);
			}
		}
		for(auto it : dead) ans.erase(it);
	}
	return ans;
}

set<int> ExprOP(string exp) { 
	set<int> ans;
	if(exp[0] >= '0' && exp[0] <= '9') {
		ans = AtomOP(exp);
	}
	else if(exp[0] == '&') {
		int p = 1;set<int> ans1;set<int> ans2;
		stack<char> br;br.push('(');
		while(!br.empty()) {
			p++;
			if(exp[p] == '(') {
				br.push('(');
			}
			else if(exp[p] == ')') {
				br.pop();
			}
		}
		ans1 = ExprOP(exp.substr(2, p-2));
		
		int q = p+2;br.push('(');
		while(!br.empty()) {
			q++;
			if(exp[q] == '(') {
				br.push('(');
			}
			else if(exp[q] == ')') {
				br.pop();
			}
		}
		ans2 = ExprOP(exp.substr(p+2, q-p-2));
		for(auto it : ans1) {
			if(ans2.count(it)) {
				ans.insert(it);
			}
		}
	}
	else if(exp[0] == '|') {
		int p = 1;set<int> ans1;set<int> ans2;
		stack<char> br;br.push('(');
		while(!br.empty()) {
			p++;
			if(exp[p] == '(') {
				br.push('(');
			}
			else if(exp[p] == ')') {
				br.pop();
			}
		}
		ans1 = ExprOP(exp.substr(2, p-2));
		int q = p+2;br.push('(');
		while(!br.empty()) {
			q++;
			if(exp[q] == '(') {
				br.push('(');
			}
			else if(exp[q] == ')') {
				br.pop();
			}
		}
		ans2 = ExprOP(exp.substr(p+2, q-p-2));
		
		ans.insert(ans1.begin(), ans1.end());
		ans.insert(ans2.begin(), ans2.end());
	}
	return ans;
}


int main() {
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin >> n;
	for(int i = 1; i <= n; i++) {
		int dn;cin >> dn;
		int num;cin >> num;
		users.insert(dn);
		for(int j = 1; j <= num; j++) {
			int attrName;cin >> attrName;
			int attrVal; cin >> attrVal;
			attrName_attrVal_users[attrName][attrVal].insert(dn);
			attrName_users[attrName].insert(dn);
		}
	}
	int m;
	cin >> m;
	for(int i = 1; i <= m; i++) {
		string exp;cin >> exp;
		set<int> ans;
		ans = ExprOP(exp);
		for(auto it : ans) {
			cout << it << " ";
		}
		cout << endl;
	}
	return 0;
}
  • 15
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
题目描述: 农夫约翰想要丈量他的 N(1≤N≤100,000)个田地的面积。他有一条长为 L(1≤L≤1,000,000)的量尺,可以用来测量在一个平面上的距离。每个田地都是一个矩形,且所有矩形的边都平行于坐标轴。每个矩形的左下角和右上角的坐标分别为 (x1,y1) 和 (x2,y2),其中 0≤x1<x2≤L,0≤y1<y2≤L。你需要编写一个程序来计算所有田地的总面积。 输入格式: 第一行包含两个整数 N 和 L。 接下来 N 行,每行包含四个整数 x1,y1,x2,y2,表示一个矩形的左下角和右上角坐标。 输出格式: 输出所有田地的总面积。 样例输入: 3 10 0 0 1 1 1 1 5 5 5 5 10 10 样例输出: 100 解题思路: 首先,根据输入的坐标信息,我们可以计算出每个矩形的面积。这个很简单,只需要将矩形的宽和高相乘即可。 然后,我们需要判断每个矩形是否与其他矩形重叠。如果重叠了,我们就需要将重叠的部分减掉。这个问题也很简单,只需要找出所有相交的矩形,计算它们重叠的面积,然后将它们的面积减掉即可。 最后,将所有矩形的面积加起来,就是所有田地的总面积了。 具体实现时,我们可以使用一个二维数组来表示每个坐标上的矩形数量。然后,我们可以对每个矩形进行遍历,找出所有与它相交的矩形,并计算它们的重叠面积。最后,将所有矩形的面积加起来即可。 参考代码:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

:SyntaxError

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值