目录
显示
题目链接
https://www.luogu.org/problem/P1955
题解
毫无悬念,这是一道签到题。
如果把所有变量看作一个点,那么相等关系就是在这两个点之间连一条边,而不等关系不与相等关系矛盾的必要条件则是:两个点不能处在同一集合中。
于是我们可以用并查集来维护这样的一个系统:如果给出一个相等关系,就合并两个集合,将所有的不等关系存储起来,在最后处理不等关系,如果两个点处于同一集合,那么这样的不等关系就不能满足。
PS:
- 由于变量下标的范围达到了 \(10^9\),所以需要离散化处理。
- 最好不要用 map 来偷懒,本蒟蒻在洛谷上交了个 \(90\) 分(第二个点一直被卡,但在bzoj上却能AC),最后吸了氧总算AC了。
- 用 C++11 的 unordered_map 来代替 map 也可以 AC(unordered_map 基于 hash,在不需要排序操作的时候效率比 map 快,但很有可能会被特别设计的数据卡掉)。
- 这次被卡常的经验说明了:STL 常数很大,有时确实会被卡常。所以能手写数据结构的话就不要冒着被卡的风险写 TLE 了(如果允许吸氧,能用 STL 偷懒的情况下何乐而不为呢,
就是调试会很麻烦)。
#include <cstdio>
#include <algorithm>
#include <unordered_map>//一定要以c++11标准编译
#include <cstring>
using namespace std;
unordered_map<int,int> num;//利用hash的unordered_map可以大大降低常数
int fa[200005];
int tj[100005][2];
int find(int a)//用递归写会爆栈,所以这里用非递归写了
{
int r=a;
while(r!=fa[r])
r=fa[r];
int i=a,j;
while(i!=r)
{
j=fa[r];
fa[i]=r;
i=j;
}
return r;
}
void unionn(int i,int j)
{
fa[j]=i;
}
void setfa()
{
for(int i=1;i<=200000;i++)
fa[i]=i;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int cnt=0,cntt=0;
num.clear();
memset(tj,0,sizeof(tj));
setfa();
int n;
scanf("%d",&n);
for(int k=1;k<=n;k++)
{
int i,j,e;
scanf("%d%d%d",&i,&j,&e);
if(num[i]==0)num[i]=++cnt;//map大法好,但常数确实大了
if(num[j]==0)num[j]=++cnt;//可以试试unordered_map?
if(e)unionn(find(num[i]),find(num[j]));
else
{
cntt++;
tj[cntt][0]=num[i];
tj[cntt][1]=num[j];
}
}
int flag=1;
for(int i=1;i<=cntt;i++)
if(find(tj[i][0])==find(tj[i][1]))
{
puts("NO");
flag=0;
break;
}
if(flag)puts("YES");
}
return 0;
}