题解 2C
- 形如「查询有向图上两个点有没有公共祖先」的问题可以用bitset,存这个点的所有祖先既可
这个题有个特殊的限制:如果两个点见有派生关系,那它们即使有公共祖先也不能算作贡献
但可以发现若两个点见有派生关系,那父节点就没有用了
所以可以按声明顺序逆序排序,如果发现这个点已经在并集里了就跳过
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1010
#define ll long long
#define reg register int
//#define int long long
int n;
namespace task1{
int top;
unordered_map<string, bool> mp;
string tem, son[N], buf;
void solve() {
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
top=0;
cin>>tem>>buf>>buf;
while (buf[0]!=';') son[++top]=buf, cin>>buf;
if (mp.find(tem)!=mp.end()) {cout<<"greska"<<endl; goto jump;}
for (int j=1; j<=top; ++j)
if (mp.find(son[j])==mp.end()) {cout<<"greska"<<endl; goto jump;}
mp[tem]=1;
cout<<"ok"<<endl;
jump: ;
}
exit(0);
}
}
namespace task{
int top, tot;
unordered_map<string, int> mp;
bitset<N> s[N], r;
string tem, son[N], buf;
void solve() {
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
top=0;
cin>>tem>>buf>>buf;
while (buf[0]!=';') son[++top]=buf, cin>>buf;
if (mp.find(tem)!=mp.end()) {cout<<"greska"<<endl; goto jump;}
for (int j=1; j<=top; ++j)
if (mp.find(son[j])==mp.end()) {cout<<"greska"<<endl; goto jump;}
sort(son+1, son+top+1, [](string a, string b) {return mp[a]>mp[b];});
r.reset();
for (int j=1,t; j<=top; ++j) if (r[t=mp[son[j]]]==0) {
if ((r&s[t]).any()) {cout<<"greska"<<endl; goto jump;}
else r|=s[t];
}
mp[tem]=++tot; s[tot]=r; s[tot][tot]=1;
cout<<"ok"<<endl;
jump: ;
}
exit(0);
}
}
signed main()
{
freopen("class.in", "r", stdin);
freopen("class.out", "w", stdout);
ios::sync_with_stdio(false);
cin>>n;
task::solve();
return 0;
}