题意:
给出一些限制形如 xi≠xj x i ≠ x j 或 xi=xj x i = x j
判断最早出现矛盾的位置(n<=1e5)
Solution:
等于关系满足传递性,可以用并查集来维护
而不等关系呢?
可以这样做:把相等元素放在一个集合里,每个集合看做一个点,出现不等关系时,我们把这两个不等元素所在的集合直接互相连边,合并两个集合时顺带处理一下与他们相连的边即可。
当给出相等条件时,判断这两个元素所在集合之间是否有边,合并两个点;
给出不等条件时,判断这两个元素是否在一个集合里,对两个元素所在集合互相连边
代码:
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
int fa[100010];
int n,x,y;
bool p;
struct edg{
int to,next;
}e[200010];
int tot,ans[100010],du[100010];
int size=1,head[100010];
int vis[200010],num;
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void cl()
{
size=1;
for (int i=1;i<=num;i++) fa[vis[i]]=vis[i],du[vis[i]]=0,head[vis[i]]=0;
num=0;
}
void add(int x,int y)
{
size++;
du[x]++;
e[size].to=y;
e[size].next=head[x];
head[x]=size;
}
bool hebing(int x,int y)
{
if (du[x]>du[y]) swap(x,y);
fa[x]=y;
du[y]+=du[x];
int lst=0;
for (int i=head[x];i;i=e[i].next)
{
int t=e[i].to;
if (t==y) return 1;
e[i^1].to=y;
lst=i;
}
if (lst)
{
e[lst].next=head[y];
head[y]=head[x];
}
return 0;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=100000;i++) fa[i]=i;
for (int i=1;i<=n;i++)
{
scanf("%d%d%d",&x,&y,&p);
vis[++num]=x,vis[++num]=y;
if (p)
{
x=find(x),y=find(y);
if (x==y) continue;
if (hebing(x,y)) cl(),ans[++tot]=i;
}
else
{
x=find(x),y=find(y);
if (x==y) cl(),ans[++tot]=i;
else add(x,y),add(y,x);
}
}
printf("%d\n",tot);
for (int i=1;i<=tot;i++) printf("%d\n",ans[i]-ans[i-1]);
}