题解 P8252 [NOI Online 2022 提高组] 讨论

先把所有集合按大小排序,设排序后的为新编号。

考虑所有会做第 i 题的人,如果存在两个人 x,y 满足 x 的新编号小于 y 且存在一道题 xy 不会,(x,y) 就是答案。否则就不存在。

考虑不存在的情况,一定形成了一条包含关系的链。所以条件可以转化为考虑 x,y 满足 yx 的后继就可以了。

如果再某一题中 x 的后继为 y,而在另一题中 x 的后继为 z(或者没有后继)。那么只要比较 y,z 新编号的大小,会发现 (x,y) 或者 (x,z) 一定满足条件了。

否则每道题 x 的后继都是一样的,肯定找不到答案了,因此不存在。

时间复杂度 O(nlogn),瓶颈在排序。可以换用桶排变为 O(n)

#include <bits/stdc++.h>
using namespace std;
const int N=2000005;
int n;
vector<int>v[N];
int a[N],ans[N];
bool cmp(int x,int y)
{
	if (a[x]==a[y]) return x<y;
	return a[x]<a[y];
}

inline int read()
{
    int F=1,ANS=0;
	char C=getchar();
    while (C<'0'||C>'9')
	{
		if (C=='-') F=-1;
		C=getchar();
	}
    while (C>='0'&&C<='9')
	{
		ANS=ANS*10+C-'0';
		C=getchar();
	}
    return F*ANS;
}

void work()
{
	n=read();
	for (int i=1;i<=n;i++) v[i].clear();
	for (int i=1;i<=n;i++) ans[i]=0;
	for (int i=1;i<=n;i++) 
	{
		a[i]=read();
		for (int j=1;j<=a[i];j++)
		{
			int x=read();
			v[x].push_back(i);
		}
	}
	a[n+1]=n+1;
	for (int i=1;i<=n;i++) v[i].push_back(n+1);
	for (int i=1;i<=n;i++) sort(v[i].begin(),v[i].end(),cmp);
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<(int)v[i].size();j++)
		{
			if (ans[v[i][j-1]]==0) ans[v[i][j-1]]=v[i][j];
			else if (ans[v[i][j-1]]!=v[i][j])
			{
				int res=ans[v[i][j-1]];
				if (cmp(v[i][j],res)) res=v[i][j];
				printf("YES\n%d %d\n",v[i][j-1],res);
				return;
			}
		}
	}
	printf("NO\n");
}

int main()
{
	int T=read();
	while (T--) work();
	return 0;
}

posted @   Little09  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示