#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P; //记录序对(i,j),即属性i,且其值为j
const int N = 2503;
int n,m,sz,id,k,c,d,x,y,num[N],to[N],f[N];
// 成员个数,表达式个数,表达式长度,成员id,成员属性个数,c操作栈栈顶, d操作数栈栈顶
//(x,y) = (i,j),操作数栈,成员序号,表达式匹配对象
map<int,int>q[N]; //q[i][j] = k ;即成员序号为DN的属性j的值为k;其中N=max(i)
//使用map而非二维数组的好处是动态申请空间减少了内存的需求
map<P,vector<int>>p; //记录属性i的值为j的成员序号,而非id,实际上也可以直接记录id
map<int,vector<int>>has; //记录属性为i的成员序号,以此减去(i,j)的成员可以起到“取反”的作用
char s[N],op[N]; //读入的匹配式,操作符栈
bitset<N>stk[N*2]; //操作数栈,
//进行& | 的操作
bitset<N>cal(int l,char x,int r){
bitset<N> ans; //使用二进制来表示对应成员的状态信息,方便进行处理
for(auto &v:p[P(l,r)]){ //遍历容器
ans.set(v);
}
if(x == '~'){
for(auto &v:has[l]){
ans.flip(v);
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&id,&k);
to[i] = id;
for(int j=1;j<=k;j++){ //此处将读入的成员信息进行预处理,方便后续计算直接调用
scanf("%d%d",&x,&y);
q[i][x] = y;
has[x].push_back(i);
p[P(x,y)].push_back(i);
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++){ //每次读入一整个字符串然后进行分析,而非一次全部读入在分析
scanf("%s",s); //这对于语句的分析有很大帮助,具有借鉴意义
sz = strlen(s);
c = d =0;
for(int j=0;j<sz;){
if(s[j] == '&'|| s[j] =='|'){
op[++c] = s[j++];
}
else if(s[j] == '('){
j++;
}
else if(s[j] == ')'){
num[c]++;
if(num[c] == 2){ //num[c]及对应当前运算符栈顶的运算符所将要处理的操作数个数
d--; //只有当达到两个的时候才进行具体的计算,不同于计算器模拟中的顺序,因地制宜
if(op[c] == '&') stk[d] = stk[d]&stk[d+1];
else stk[d] = stk[d]|stk[d+1];
num[c--] = 0; //释放栈空间
}
j++;
}
else
{
int cur = j,l=0,r =0;
while(cur<sz&&(s[cur]!=':'&&s[cur]!='~')){
l = l*10 + (s[cur]-'0');
cur++;
}
char x = s[cur++];
while(cur<sz&&s[cur]!=')'){
r = r*10+(s[cur]-'0');
cur++;
}
stk[++d] = cal(l,x,r);
j = cur;
}
}
int e =0;
for(int j=1;j<=n;j++)
{
if(stk[d].test(j))
f[++e] = to[j];
}
sort(f+1,f+e+1);
for(int j=1;j<=e;j++)
printf("%d%c",f[j]," \n"[j==e]); //根据当前状况进行选择性输出
if(!e) puts("");
}
return 0;
}
本代码优点在于使用容器进行存储,节省了空间。其次,对数据在输入时进行预处理,方便进行后续的计算处理。