「题解」CF1468M Similar Sets
Posted Lu_Anlai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「题解」CF1468M Similar Sets相关的知识,希望对你有一定的参考价值。
本文将同步发布于:
题目
题意简述
给定 \\(n\\) 个集合 \\(S_{1\\sim n}\\),问是否存在 \\(i,j\\) 满足 \\(i\\neq j\\) 且 \\(\\left\\lvert S_i\\cap S_j\\right\\rvert\\geq 2\\)。
若存在,输出 \\(i,j\\)(任意一对都可);否则输出 \\(-1\\)。
\\(n\\leq 10^5\\),\\(\\sum\\limits_{i=1}^n\\left\\lvert S_i\\right\\rvert\\leq 2\\times 10^5\\)。
题解
图论转化
直接思考有点难,考虑经典套路,我们把这个问题转化成二分图模型。
对于一个集合 \\(S_i\\),我们将其构造为一个左部点 \\(i\\)。
对于一个元素 \\(x\\),我们将其构造为一个右部点 \\(x\\)。
如果 \\(x\\in S_i\\),那么图上有一条边 \\((i,x)\\)。
那么 \\(\\left\\lvert S_i\\cap S_j\\right\\rvert\\geq 2\\),就对应有至少两个右部点连到了同样的两个点。
换句话说,符合条件的答案对应了图中的一个四元环。
并且,这张图的度数总和为 \\(\\sum\\limits_{i=1}^n\\left\\lvert S_i\\right\\rvert\\)。
按点的度数分治
现在我们要解决的问题就是一个二分图内是否存在四元环。
这同样是一个简单的问题,具体地,我们考虑按点的度数分治:
- 找到一个非负整数 \\(B\\);
- 称度数 \\(\\geq B\\) 的为大点,度数 \\(< B\\) 的为小点;
- 对于大点,其个数为 \\(\\Theta\\left(\\frac{\\sum\\texttt{deg}}{B}\\right)\\)。
我们对于每个大左部点,标记其所有相连点,如果存在另一个左部点,其连接的标记点个数 \\(\\geq 2\\),那么存在一个四元环。
我们对于每个小左部点,我们枚举其对应的所有的右部点对,然后对于每一个点对,我们枚举其最小值,然后标记其对应点,如果一个点在之前被标记过,那么就存在一个四元环。
根据上面的分析,我们得出算法的时间复杂度为 \\(\\Theta\\left(\\frac{\\sum\\texttt{deg}}{B}\\sum\\texttt{deg}+B\\sum\\texttt{deg}\\right)\\)。
理论分析可以得出,最优的时间复杂度为 \\(\\Theta\\left(\\sum\\texttt{deg}\\sqrt{\\sum\\texttt{deg}}\\right)\\)。
参考程序
#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
#define flush() (fwrite(wbuf,1,wp1,stdout),wp1=0)
#define putchar(c) (wp1==wp2&&(flush(),0),wbuf[wp1++]=c)
static char wbuf[1<<21];int wp1;const int wp2=1<<21;
inline int read(void){
reg char ch=getchar();
reg int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=10*res+(ch^\'0\'),ch=getchar();
return res;
}
inline void write(reg int x){
static char buf[32];
reg int p=-1;
if(x<0) x=-x,putchar(\'-\');
if(!x) putchar(\'0\');
else while(x) buf[++p]=(x%10)^\'0\',x/=10;
while(~p) putchar(buf[p--]);
return;
}
const int MAXN=1e5+5;
const int MAXS=2e5+5;
struct Event{
int x,y,id;
inline Event(reg int x=0,reg int y=0,reg int id=0):x(x),y(y),id(id){
return;
}
};
struct Link{
int val,id;
inline Link(reg int val=0,reg int id=0):val(val),id(id){
return;
}
};
int n;
inline pair<int,int> solve(void){
n=read();
reg int sum=0;
vector<vector<int>> S(n+1);
vector<int> V;
for(reg int i=1;i<=n;++i){
reg int k=read();
sum+=k;
S[i].resize(k);
for(reg int j=0;j<k;++j)
S[i][j]=read(),V.push_back(S[i][j]);
}
sort(V.begin(),V.end()),V.erase(unique(V.begin(),V.end()),V.end());
for(reg int i=1;i<=n;++i)
for(int& x:S[i])
x=lower_bound(V.begin(),V.end(),x)-V.begin();
reg int m=V.size();
reg size_t B=sqrt(sum/16);
vector<int> Big,Sma;
for(int i=1;i<=n;++i)
if(S[i].size()>=B)
Big.push_back(i);
else
Sma.push_back(i);
vector<bool> vis(m);
vis.resize(m);
for(reg int i=0,siz=Big.size();i<siz;++i){
int u=Big[i];
for(int x:S[u])
vis[x]=true;
for(reg int j=1;j<=n;++j){
int v=j;
if(u!=v){
reg int cnt=0;
for(int x:S[v])
if(vis[x])
++cnt;
if(cnt>=2)
return make_pair(u,v);
}
}
for(int x:S[u])
vis[x]=false;
}
vector<Event> E;
for(reg int i=0,siz=Sma.size();i<siz;++i){
reg int u=Sma[i];
for(reg int j=0,siz=S[u].size();j<siz;++j)
for(reg int k=j+1;k<siz;++k)
E.push_back(Event(S[u][j],S[u][k],u));
}
vector<vector<Link>> G;
G.resize(m);
for(Event e:E)
if(e.x<e.y)
G[e.x].push_back(Link(e.y,e.id));
else
G[e.y].push_back(Link(e.x,e.id));
vector<int> from;
from.resize(m);
for(reg int i=0;i<m;++i){
for(Link L:G[i])
if(!from[L.val])
from[L.val]=L.id;
else
return make_pair(from[L.val],L.id);
for(Link L:G[i])
from[L.val]=0;
}
return make_pair(-1,-1);
}
int main(void){
reg int t=read();
while(t--){
static pair<int,int> ans;
ans=solve();
if(ans.first==-1)
write(-1),putchar(\'\\n\');
else
write(ans.first),putchar(\' \'),write(ans.second),putchar(\'\\n\');
}
flush();
return 0;
}
以上是关于「题解」CF1468M Similar Sets的主要内容,如果未能解决你的问题,请参考以下文章
cf1080F. Katya and Segments Sets