后面会发出 AC 代码(肯定是别人的)。依赖于空行进行读入所以记得加上。
// Problem: UVA10757 Interpreting SQL
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/UVA10757
// Memory Limit: 0 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <string>
#include <queue>
#include <iostream>
#include <vector>
#include <map>
#include <set>
using namespace std;
struct Info{
int typ;
int typ_int;
string typ_str;
Info(int typ=0, int typ_int=0, string typ_str="")
:typ(typ), typ_int(typ_int), typ_str(typ_str){}
bool operator < (const Info& x)const{
if(typ == 0)
return typ_int < x.typ_int;
return typ_str < x.typ_str;
}
bool operator > (const Info& x)const{
return x < (*this);
}
bool operator <= (const Info& x)const{
return !((*this) > x);
}
bool operator >= (const Info& x)const{
return !((*this) < x);
}
bool operator == (const Info& x)const{
if(typ != x.typ) return false;
return ((*this) >= x) && ((*this) <= x);
}
bool operator != (const Info& x)const{
return !((*this) == x);
}
};
inline string toU(string s){
for(auto& x: s)
if(x>='a' && x<='z')
x = x-'a'+'A';
return s;
}
inline bool chk(Info l, string cmp, Info r){
if(cmp == "=") return l == r;
if(cmp == ">") return l > r;
if(cmp == "<") return l < r;
if(cmp == ">=") return l >= r;
if(cmp == "<=") return l <= r;
return l != r;
}
struct Table{
vector<pair<string, char> > Col;
map<string, int> Mp;
vector<vector<Info> > In;
string name;
int Sr, Sc;
Table(){
Sr = Sc = 0;
name = "";
In.clear();
Mp.clear();
Col.clear();
}
void read(){
cin >> name >> Sr >> Sc;
string s; char ch;
for(int i=0; i<Sr; i++){
cin >> s >> ch;
Col.emplace_back(s, ch);
Mp[toU(s)] = i;
}
In.resize(Sc);
for(auto& x: In) x.resize(Sr);
int tI = 0; string tR = "";
for(int i=0; i<Sc; i++){
for(int j=0; j<Sr; j++){
if(Col[j].second == 'I') cin >> tI;
else cin >> tR;
In[i][j] = Info(Col[j].second == 'S', tI, tR);
tI = 0; tR = "";
}
}
}
inline bool check(vector<Info>& x, Info l, string cmp, Info r){
if(l.typ == 2) l = x[Mp[toU(l.typ_str)]];
if(r.typ == 2) r = x[Mp[toU(r.typ_str)]];
return chk(l, cmp, r);
}
inline Table& filter(Info a, string cmp, Info b){
vector<vector<Info> > newInfo;
newInfo.clear();
for(auto x: In){
Info l = a;
Info r = b;
if(check(x, l, cmp, r))
newInfo.push_back(x);
}
Sc = newInfo.size();
In = newInfo;
return *this;
}
inline void print(vector<string> op){
if(op[0] == "*"){
printf("%d %d\n", Sr, Sc);
for(auto& x: Col)
printf("%s\n", x.first.c_str());
for(auto& x: In){
bool qq = 0;
for(auto a: x){
if(qq) printf(" ");
qq = true;
if(a.typ == 0) printf("%d", a.typ_int);
else printf("%s", a.typ_str.c_str());
}
printf("\n");
}
}
else{
printf("%d %d\n", (int)op.size(), Sc);
for(auto& x: op)
printf("%s\n", Col[Mp[toU(x)]].first.c_str());
for(auto& x: In){
bool qq = false;
for(auto q: op){
if(qq) printf(" ");
qq = true;
Info a = x[Mp[toU(q)]];
if(a.typ == 0) printf("%d", a.typ_int);
else printf("%s", a.typ_str.c_str());
}
printf("\n");
}
}
}
};
map<string, Table> tableMp;
Table mergeTable(Table& x, Table& y){
Table ret;
ret.Sr = x.Sr + y.Sr;
ret.Sc = x.Sc * y.Sc;
vector<Info> vec(0);
for(int i=0; i<ret.Sr; i++) vec.push_back(Info());
for(int i=0; i<ret.Sc; i++)
ret.In.push_back(vec);
for(auto q: x.Col) ret.Col.push_back(q);
for(auto q: y.Col) ret.Col.push_back(q);
for(int i=0; i<ret.Sr; i++)
ret.Mp[toU(ret.Col[i].first)] = i;
for(int i=0; i<x.Sc; i++)
for(int j=0; j<y.Sc; j++){
int p = i * y.Sc + j;
for(int k=0; k<x.Sr; k++)
ret.In[p][k] = x.In[i][k];
for(int k=0; k<y.Sr; k++)
ret.In[p][k+x.Sr] = y.In[j][k];
}
return ret;
}
int T, N;
vector<string> symbols{"(", ")", "<=", ">=", "<", ">", "=", "<>", ","};
set<string> symbolList(symbols.begin(), symbols.end());
struct Tokens{
string s = "";
int typ = -1;
bool over = false;
inline Tokens& get(){
s = ""; typ = -1;
if(over) return *this;
char ch;
do{
ch = getchar();
}while(ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
if(ch == '\0' || ch == EOF){
over = true;
return *this;
}
else if(ch == '\"'){
typ = 1;
while(1){
ch = getchar();
if(ch == '\"') break;
if(ch == '\\') ch = getchar();
s += ch;
}
}
else if(isdigit(ch)){
typ = 0;
s += ch;
while(1){
ch = getchar();
if(!isdigit(ch)) break;
s += ch;
}
ungetc(ch, stdin);
}
else if(isalpha(ch)){
typ = 2;
s += ch;
while(1){
ch = getchar();
if(!isalpha(ch) && !isdigit(ch)) break;
s += ch;
}
ungetc(ch, stdin);
}
else{
typ = 3;
s += ch;
ch = getchar();
if(symbolList.count(s + ch)){
s += ch;
ch = getchar();
}
ungetc(ch, stdin);
}
return *this;
}
inline Info status(){
return Info(typ, (typ==0?atoi(s.c_str()):0), (typ==0?"":s));
}
}Tkns;
vector<string> getOption;
vector<Info> whereOption;
vector<pair<string, bool> > orderOption;
vector<int> whereBracket;
Table currTable;
inline bool whereFilter(vector<Info>& x, int l, int r){
while(whereBracket[l] == r) ++l, --r;
bool ret = false;
int u = r;
if(whereBracket[u] != -1) u = whereBracket[u];
else u = r - 2;
if(u == r - 2){
ret = currTable.check(x
, whereOption[u]
, whereOption[u+1].typ_str
, whereOption[r]);
}
else ret = whereFilter(x, u, r);
while(u > l && whereOption[u-1] == Info(2, 0, "NOT"))
ret ^= 1, --u;
--u;
if(u < l) return ret;
if(whereOption[u] == Info(2, 0, "AND"))
return whereFilter(x, l, u-1) && ret;
return whereFilter(x, l, u-1) || ret;
}
inline bool orderCmp(vector<Info>& l, vector<Info>& r){
for(auto x: orderOption){
Info L = l[currTable.Mp[toU(x.first)]];
Info R = r[currTable.Mp[toU(x.first)]];
if(L != R) return (L < R) ^ x.second;
}
return false;
}
int main(){
cin >> T;
Tkns.get();
bool ee = false;
while(T--){
if(ee) printf("\n");
ee = true;
N = atoi(Tkns.s.c_str());
tableMp.clear();
for(int i=0; i<N; i++){
Table t; t.read();
tableMp[toU(t.name)] = t;
}
// SELECT
Tkns.get();
// [argv]
getOption.clear();
getOption.push_back(Tkns.get().s);
while(Tkns.get().status() == Info(3, 0, ","))
getOption.push_back(Tkns.get().s);
// [from item]
int Q = 0;
vector<Table> tStk; tStk.clear();
bool ww = true;
while(1){
string q = Tkns.get().s;
int r = Tkns.typ;
if((q == "(" || q == ")") && r == 3){
Q += (q == "(" ? 1 : -1);
continue;
}
if(q == "INNER" && r == 2 && !ww){
Tkns.get();
ww = true;
continue;
}
if(q == "ON" && r == 2 && !ww){
Tkns.get();
Info a = Tkns.status();
Tkns.get(); Tkns.get();
Info b = Tkns.status();
Table r = tStk.back(); tStk.pop_back();
Table l = tStk.back(); tStk.pop_back();
tStk.push_back(mergeTable(l, r).filter(a, "=", b));
continue;
}
if(!ww) break;
tStk.push_back(tableMp[toU(q)]);
ww = false;
}
currTable = tStk.back();
if(Tkns.s == "WHERE"){
whereOption.clear();
bool ndO = true, lasN = false;
int brk = 0;
while(1){
Tkns.get();
whereOption.push_back(Tkns.status());
if(Tkns.s == "(" && Tkns.typ == 3) ++brk, lasN = false;
else if(Tkns.s == ")" && Tkns.typ == 3) --brk, lasN = false;
else if(Tkns.s == "NOT" && Tkns.typ == 2 && ndO) lasN = true;
else if(((Tkns.s == "AND" || Tkns.s == "OR"))
&& Tkns.typ == 2 && !ndO) ndO = true, lasN = false;
else if(!ndO && !brk) break;
else{
if(Tkns.typ != 3){
Tkns.get();
whereOption.push_back(Tkns.status());
}
ndO = lasN = false;
Tkns.get();
whereOption.push_back(Tkns.status());
}
}
whereOption.pop_back();
vector<vector<Info> > newInfo; newInfo.clear();
whereBracket.clear();
whereBracket.resize(whereOption.size(), -1);
vector<int> whereStk; whereStk.clear();
for(int i=0; i<(int)whereOption.size(); i++){
if(whereOption[i] == Info(3, 0, "("))
whereStk.push_back(i);
if(whereOption[i] == Info(3, 0, ")"))
whereBracket[i] = whereStk.back(),
whereBracket[whereStk.back()] = i,
whereStk.pop_back();
}
for(auto x: currTable.In){
if(whereFilter(x, 0, whereOption.size()-1))
newInfo.push_back(x);
}
currTable.Sc = newInfo.size();
currTable.In = newInfo;
}
if(Tkns.s == "ORDER"){
Tkns.get();
orderOption.clear();
while(1){
string f; bool p = false;
f = Tkns.get().s;
Tkns.get();
if(Tkns.s == "ASCENDING"){
p = false; Tkns.get();
}
if(Tkns.s == "DESCENDING"){
p = true; Tkns.get();
}
orderOption.emplace_back(f, p);
if(Tkns.s != ",") break;
}
sort(currTable.In.begin(), currTable.In.end(), orderCmp);
}
currTable.print(getOption);
}
return 0;
}