题解 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;
}
posted @ 2021-09-20 19:06  Administrator-09  阅读(4)  评论(0编辑  收藏  举报