并查集/带权并查集/离散化

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define IOS   std::ios::sync_with_stdio(0) , cin.tie(0);
using namespace std;

const int maxn = 5e4 + 5;
int fa[maxn], Rank[maxn], num[maxn], N, M, cnt, n; //Rank数组表示x到fa[x]的奇偶性
struct Edge { //结构体存区间顺序,va表示奇数还是偶数
    int x, y, va;
} edge[maxn];

int search(int x) {    //二分快速查找x在num数组的顺序
    int left = 0, right = n;
    while (left + 1 < right) {
        int mid = (left + right) >> 1;
        if (num[mid] == x)
            return mid;
        if (num[mid] < x)
            left = mid;
        else
            right = mid;
    }
    if (num[left] == x)
        return left;
    else
        return right;
}

int query(int x) { //路径压缩     带权并查集
    if (x != fa[x]) {
        int per = fa[x];
        fa[x] = query( fa[x] );
        Rank[x] = (Rank[x] + Rank[per]) % 2;  
    }
    return fa[x];
}

void inti() {
    for (int i = 1; i <= cnt; ++i) {
        fa[i] = i;
     //   Rank[i] = 0;
    }
}
int main() {
    
   // std::ios::sync_with_stdio(0), cin.tie(0),cout.tie(0);
    cin >> N >> M;
    char str[20]; 
    cnt = 0;
    for (int i = 0; i < M; i++) {
        cin >> edge[i].x >> edge[i].y >> str;
        edge[i].x--; //连续
        if (str[0] == 'e') 
            edge[i].va = 0; //odd even 处理
        else
            edge[i].va = 1;
        num[cnt++] = edge[i].x; //存入num数组离散化
        num[cnt++] = edge[i].y; //
    }
    inti();
    sort(num, num + cnt);
    n = unique(num, num + cnt) - num; //unique函数的作用是去重,并且返回数组的迭代器,再减去数组num的地址就是新数组的长度
  
    int i;
    for (i = 0; i < M; i++) {
        int pa = search(edge[i].x);
        int pb = search(edge[i].y);
       
        int X = query(pa);
        int Y = query(pb);
        if (X == Y) {        //
            if ( (Rank[pa] + Rank[pb] + 2) % 2 != edge[i].va) { //两种路径的奇偶性必须相等
                cout << i;
                return 0;
            }
        }
        else {
            fa[Y] = X; //在x,y中直接连一条线的权
            Rank[Y] = (Rank[pa] - Rank[pb] + edge[i].va +2 ) % 2; //合并
        }
    }
    
    cout << M;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值