传送门

题意:

给出一些限制形如 xixj 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]);
}