M. Similar Sets 题解(根号分治)
题目链接
题目大意
就是给你\(n\)个集合,所有集合的元素数量不超过\(2e5\)
找出两个集合使得这两个集合至少拥有两个相同的元素,输出任意一组解即可
题目思路
这个写法 真玄学
俗称根号分治 就是对于集合元素的数量进行分类
我是直接看这份题解的链接
对于n个点对的重复问题,确实可以使用\(O(n)\)
比用\(map<pii,int>\)好得多
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=998244353,lim=300;
const double eps=1e-6;
int n,m,k;
int cnt=0;
unordered_map<int,int> ls;
vector<int> g[maxn];
vector<int> b,s;
vector<pair<int,int>> vec[maxn];
int vis[maxn];
int lisan(int x){
if(ls[x]==0){
ls[x]=++cnt;
}
return ls[x];
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
int _;cin>>_;
while(_--){
cnt=0;
ls.clear();
b.clear();
s.clear();
cin>>n;
for(int i=1;i<=n;i++){
g[i].clear();
cin>>k;
for(int j=1,x;j<=k;j++){
cin>>x;
x=lisan(x);
g[i].push_back(x);
}
if(k>=lim){
b.push_back(i);
}else{
s.push_back(i);
}
}
for(int i=1;i<=cnt;i++){
vec[i].clear();
}
bool flag=0;
for(auto id:b){
if(flag) break;
for(int j=0;j<g[id].size();j++){
int x=g[id][j];
vis[x]=1;
}
for(int i=1;i<=n;i++){
if(i==id) continue;
int cnt=0;
for(int j=0;j<g[i].size();j++){
cnt+=vis[g[i][j]];
}
if(cnt>=2){
cout<<i<<" "<<id<<'\n';
flag=1;
break;
}
}
for(int j=0;j<g[id].size();j++){
int x=g[id][j];
vis[x]=0;
}
}
for(auto id:s){
if(flag) break;
for(int j=0;j<g[id].size();j++){
if(flag) break;
for(int k=j+1;k<g[id].size();k++){
int x=g[id][j],y=g[id][k];
if(x>y) swap(x,y);
vec[x].push_back({y,id});
}
}
}
for(int i=1;i<=cnt;i++){
if(flag) break;
for(auto j:vec[i]){
int x=j.fi,y=j.se;
if(vis[x]){
cout<<vis[x]<<" "<<y<<'\n';
flag=1;
break;
}
vis[x]=y;
}
for(auto j:vec[i]){
int x=j.fi,y=j.se;
vis[x]=0;
}
}
if(!flag){
cout<<-1<<'\n';
}
}
return 0;
}
不摆烂了,写题