练习并查集必做系列。
题目给定的操作有\(2\)种:相等或不相等。
这里没有要求实时查询,所以(对于每组数据)打乱查询顺序也无可厚非。
一次我们不妨先处理\(e=1\)的情况,将信息存入并查集中。
再取\(e=0\)的情况,如果\(find(x)==find(y)\),那么该逻辑不合法。
如果从头到脚都是合法的,就是判定为可以被满足的。
代码:
#include<cstdio>
using namespace std;
const int N=1e7+10;
const int M=1e5+10;
int uset[N];
int find(int x){
return (uset[x]==x)?x:uset[x]=find(uset[x]);
}
inline void merge(int x,int y){
uset[find(y)]=find(x);
}
int x[M],y[M],e[M];
int m,T;
int main()
{
scanf("%d",&T);
while(T--)
{
register int i;
bool flag=1;
scanf("%d",&m);
for(i=1;i<=m;i++)scanf("%d%d%d",&x[i],&y[i],&e[i]);
for(i=1;i<=N;i++)uset[i]=i;
for(i=1;i<=m;i++)
{
if(!e[i])continue;
merge(x[i],y[i]);
}
for(i=1;i<=m&&flag;i++)
{
if(e[i])continue;
if(find(x[i])==find(y[i]))flag=0;
}
if(flag)puts("YES");
else puts("NO");
}
return 0;
}
\(\text{But----}\)
什么玩意儿?!
我们再瞄一眼数据规模:
难道开1e9的数组。。。
我们也许会使用map
这种神奇的STL,这是一种极为省力的方法。
map
版Code(不解释了。):
#include<cstdio>
#include<map>
using namespace std;
const int MAX_N=1e5+1;
map<int,int>num;
int n;
int x[MAX_N],y[MAX_N];
int b[MAX_N];
int fa[MAX_N*2];
int find(int x){return (fa[x]==x)?x:fa[x]=find(fa[x]);}
inline void merge(int x,int y){fa[find(x)]=find(y);}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
register int i;
bool flag=0;
int cnt=0;
scanf("%d",&n);
num.clear();
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&x[i],&y[i],&b[i]);
if(num.find(x[i])==num.end())num[x[i]]=++cnt;
if(num.find(y[i])==num.end())num[y[i]]=++cnt;
}
for(i=1;i<=cnt;i++)fa[i]=i;
for(i=1;i<=n;i++)
{
if(!b[i])continue;
merge(num[x[i]],num[y[i]]);
}
for(i=1;i<=n;i++)
{
if(b[i])continue;
if(find(num[x[i]])==find(num[y[i]]))
{
flag=1;
break;
}
}
if(flag)puts("NO");
else puts("YES");
}
}
\(Result->\)
效果不差!但是这样的时间并不是最高效的,而且如果在Luogu上评测,还极有可能T掉一个点。
考虑到map
的(1次)加入和查找操作的时间复杂度\(O(\log_2 n)\),这将造成大量的时间消耗!
所以这里有一个一次性搞定的方法。
输入时,将\(x_i,x_j\)中的\(i,j\)存入数组
nums
中(此处nums
要开到2e5
的大小)。然后将
nums
数组排序,然后去重(在#include<algorithm>
库中有sort
函数(排序)和unique
函数(去重))。接下来将输入的数据_映射成这个数据在_
nums
中的下标(听说lower_bound
很好用呵~)。此时此刻,初始数据已经成为了大小在\([1,2\times 10^5]\)中的整数!
然后开2e5的并查集,进行上述的算法。
\[\text{MainCodeHere}\]
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAX_N=1e5+10;
int uset[MAX_N*2];
int x[MAX_N],y[MAX_N],e[MAX_N];
int nums[MAX_N*2];
int n,total;
int find(int x){
return (x==uset[x])?x:uset[x]=find(uset[x]);
}
inline void merge(int x,int y){
int fx=find(x),fy=find(y);
if(fx==fy)return;
uset[fx]=fy;return;
}
signed main()
{
int T;scanf("%d",&T);
while(T--)
{
register int i;
total=-1;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&x[i],&y[i],&e[i]);
nums[++total]=x[i];
nums[++total]=y[i];
}
sort(nums,nums+total);
int tmp=unique(nums,nums+total)-nums;
total=tmp;
for(i=1;i<=n;i++)
{
x[i]=lower_bound(nums,nums+total,x[i])-nums;
y[i]=lower_bound(nums,nums+total,y[i])-nums;
}
for(i=0;i<=total;i++)uset[i]=i;
for(i=1;i<=n;i++)
if(e[i])
merge(x[i],y[i]);
bool flag=1;
for(i=1;i<=n&&flag;i++)
if(!e[i]&&find(x[i])==find(y[i]))
flag=0;
if(flag)puts("YES");
else puts("NO");
}
return 0;
}
perfect!