Codeforces 1468M. Similar Sets

传送门

题目大意

给定 \(n(2\le n\le10^5)\) 个集合,每个集合大小为 \(k_i(2\le k_i\le10^5,\sum k\le2\cdot10^5)\) ,集合内每个元素 \(1\le a_{ij}\le10^9\) 。求一对集合,其交集大小至少为 \(2\)

思路

考虑根号分治,我们先进行离散化,之后对于 \(k_i>\sqrt{\sum k}\) 的集合,将所有元素放入桶里维护,接着我们可以枚举其他所有集合,检查是否存在一个集合有两个元素与之相同即可,待检查的集合数量不超过 \(\sqrt{\sum k}\) ,于是这部分复杂度 \(O(\sum k\sqrt{\sum k})\)
在考虑另一部分集合,我们可以预处理出每个集合中所有出现的二元组,最后只要检查是否存在两个相同的二元组即可。这些集合的二元组数量总和为 \(\sum{\frac{k(k-1)}{2}}\) ,将所有二元组按第一维建桶,最后检查时扫描每个桶看是否存在两个相同的第二维即可,此外还要记录每个二元组所属的集合,最后这一部分的复杂度也为 \(O(\sum k\sqrt{\sum k})\)

代码

#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<int, int>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mk make_pair
//#define int LL
//#define double LD
//#define lc p*2
//#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-10;
const LL MOD = 1000000007;
const LL mod = 998244353;
const int maxn = 100010;
const int maxm = 200010;

int T, N, M, K[maxn];
vector<int>A[maxn];
int tota = 0, totb = 0;
int a[maxn], b[maxn];
int vis[maxm];
vector<PII>B[maxm];

int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		x = x * 10 + c - '0';
		c = getchar();
	}

	return x * f;
}

void write(int x)
{
	if (x < 0)
	{
		putchar('-');
		x = -x;
	}
	if (x > 9)
		write(x / 10);
	putchar(x % 10 + '0');
}

int compress()
{
	vector<int>v;
	for (int i = 1; i <= N; i++)
	{
		for (auto& x : A[i])
			v.push_back(x);
	}
	sort(all(v));
	v.erase(unique(all(v)), v.end());
	for (int i = 1; i <= N; i++)
	{
		for (auto& x : A[i])
			x = upper_bound(all(v), x) - v.begin();
	}
	return v.size();
}

void solve()
{
	tota = totb = 0;
	int sum = 0;
	for (int i = 1; i <= N; i++)
	{
		K[i] = read() , sum += K[i];
		int num;
		for (int j = 1; j <= K[i]; j++)
			num = read(), A[i].push_back(num);
	}
	M = compress();
	int base = sqrt(sum) / 2;
	for (int i = 1; i <= N; i++)
	{
		if (K[i] > base)
			a[++tota] = i;
		else
			b[++totb] = i;
	}
	for (int c = 1; c <= tota; c++)
	{
		for (int k = 0; k < K[a[c]]; k++)
			vis[A[a[c]][k]] = 1;
		for (int i = 1; i <= N; i++)
		{
			if (i == a[c])
				continue;
			int cnt = 0;
			for (int j = 0; j < K[i]; j++)
			{
				cnt += vis[A[i][j]];
				if (cnt >= 2)
				{
					printf("%d %d\n", a[c], i);
					for (int k = 0; k < K[a[c]]; k++)
						vis[A[a[c]][k]] = 0;
					return;
				}
			}
		}
		for (int k = 0; k < K[a[c]]; k++)
			vis[A[a[c]][k]] = 0;
	}
	for (int i = 1; i <= M; i++)
		B[i].clear();
	for (int i = 1; i <= totb; i++)
	{
		for (int j = 0; j < K[b[i]]; j++)
		{
			for (int k = j + 1; k < K[b[i]]; k++)
			{
				int x = A[b[i]][j], y = A[b[i]][k];
				if (x > y)
					swap(x, y);
				B[x].push_back(PII(y, b[i]));
			}
		}
	}
	for (int i = 1; i <= M; i++)
	{
		if (B[i].size() < 2)
			continue;
		for (int z = 0; z < B[i].size(); z++)
		{
			if (!vis[B[i][z].first])
				vis[B[i][z].first] = B[i][z].second;
			else
			{
				printf("%d %d\n", vis[B[i][z].first], B[i][z].second);
				for (int k = 0; k < B[i].size(); k++)
					vis[B[i][k].first] = 0;
				return;
			}
		}
		for (int k = 0; k < B[i].size(); k++)
			vis[B[i][k].first] = 0;
	}
	puts("-1");
}

int main()
{
	T = read();
	while (T--)
	{
		N = read();
		for (int i = 1; i <= N; i++)
			A[i].clear();
		solve();
	}

	return 0;
}
posted @ 2022-07-13 10:06  Prgl  阅读(43)  评论(0编辑  收藏  举报